【AWS】Ansible & KanikoでECRにDockerイメージをpushする
Kubernetesクラスタ上でDockerイメージをビルド&プッシュするためのツール「Kaniko」について、仕様を調査したのでメモ。
Kanikoとは
実体はKubernetesクラスタ上でDockerイメージをビルド、プッシュを行うためのOSSのDockerイメージです。
Googleが開発しているようですが、公式サポートはしていないようです。
READMEを見ると各クラウド環境のレジストリへのプッシュにも対応しており、使いやすそうな印象です。
前提条件
前回使用したEC2、ECR、ソースコードをそのまま使用します。
Ansibleで直接ECRにプッシュしていた箇所を、Kanikoポッドでプッシュするように変更してみます。
KanikoポッドがECRにイメージをプッシュするには、稼働環境(EC2/EKS)にIAMロールを付与するか、IAMロールが付与されたユーザーのクレデンシャルをコンテナに渡す必要があります。
今回は前回と同じユーザーを使用するため、クレデンシャルのSecretを作成しました。
$ k create secret generic aws-secret --from-file=.aws/credentials -n ansible-test
AWS ECR周りの設定は、この辺りに詳細が記載されています。
ディレクトリ構成
.
├─ deploy-image.yml 実行するAnsible playbook
├─ Dockerfile プッシュするイメージのDockerfile
├─ Jenkinsfile イメージに含めるJenkinsfile
├─ inventory
│ └─ hosts
└─ roles
└─ k8s-kaniko
└─ tasks
├─ kaniko.yml Kanikoポッドを立ち上げる為のマニフェスト
└─ main.yml Ansibleのロール
実装
記載のないファイルの内容は前回と同様です。
deploy-image.yml
roleを含めるだけのplaybookです。
--- - name: k8s kaniko Test hosts: local roles: - k8s-kaniko
roles/k8s-kaniko/tasks/main.yml
DockerfileとJenkinsfileをKanikoコンテナに渡す必要があるため、ConfigMapにしてからVolume経由でコンテナに渡す想定です。
1つのConfigMapに纏めようとしたのですが、yamlのパースエラーが起きるので2つに分けています。
改行+インデントがうまく設定できるようなコマンドを含めれば解消できそうですが、今回はそこまでの作りこみはしません。
--- - name: "Build docker image in k8s cluster" debug: msg: "Build docker image in k8s cluster" - name: Install boto3 pip: name: boto3 state: present - name: Slurp Dockerfile slurp: path: Dockerfile register: cat_Dockerfile - name: Slurp Jenkinsfile slurp: path: Jenkinsfile register: cat_Jenkinsfile - name: Create config-map in Dockerfile k8s: kubeconfig: ~/.kube/config state: present resource_definition: apiVersion: v1 kind: ConfigMap metadata: name: kaniko-test-cm-docker namespace: ansible-test data: Dockerfile: "{{ cat_Dockerfile.content | b64decode }}" - name: Create config-map in Jenkinsfile k8s: kubeconfig: ~/.kube/config state: present resource_definition: apiVersion: v1 kind: ConfigMap metadata: name: kaniko-test-cm-jenkins namespace: ansible-test data: Jenkinsfile: "{{ cat_Jenkinsfile.content | b64decode }}" - name: Create repository ecs_ecr: name: "{{ image_name }}" aws_access_key: "{{ key_id }}" aws_secret_key: "{{ access_key }}" region: "{{ region }}" register: ecr_repo - name: Push docker image vars: imagename: "{{ ecr_repo.repository.repositoryUri }}:{{ image_version }}" namespace: ansible-test k8s: definition: '{{ item }}' kubeconfig: ~/.kube/config state: present loop: - "{{ lookup('template', 'kaniko.yml') | from_yaml_all | list }}"
kaniko.yml
Kanikoポッドを立ち上げる為のマニフェストファイルです。
使い方の詳細はGitHubのREADMEに記載されています。
apiVersion: v1 kind: Pod metadata: name: kaniko namespace: {{namespace}} spec: restartPolicy: Never containers: - name: kaniko image: gcr.io/kaniko-project/executor:latest args: - "--dockerfile=./Dockerfile" - "--context=/kaniko-test-cm" - "--destination={{ imagename }}" volumeMounts: - name: aws-secret mountPath: /root/.aws readOnly: true - name: kaniko-test-cm mountPath: /kaniko-test-cm readOnly: true volumes: - name: aws-secret secret: secretName: aws-secret - name: kaniko-test-cm projected: sources: - configMap: name: kaniko-test-cm-docker - configMap: name: kaniko-test-cm-jenkins
playbook実行
正常終了することを確認。
$ ansible-playbook deploy-image.yml -i inventory/hosts
PLAY [k8s kaniko Test] *************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************
ok: [localhost]
TASK [k8s-kaniko : Build docker image in k8s cluster] ******************************************************************
ok: [localhost] => {
"msg": "Build docker image in k8s cluster"
}
TASK [k8s-kaniko : Install boto3] **************************************************************************************
ok: [localhost]
TASK [k8s-kaniko : Slurp Dockerfile] ***********************************************************************************
ok: [localhost]
TASK [k8s-kaniko : Slurp Jenkinsfile] **********************************************************************************
ok: [localhost]
TASK [k8s-kaniko : Create config-map in Dockerfile] ********************************************************************
ok: [localhost]
TASK [k8s-kaniko : Create config-map in Jenkinsfile] *******************************************************************
ok: [localhost]
TASK [k8s-kaniko : Create repository] **********************************************************************************
ok: [localhost]
TASK [k8s-kaniko : Push docker image] **********************************************************************************
changed: [localhost] => (item=[{u'kind': u'Pod', u'spec': {u'restartPolicy': u'Never', u'volumes': [{u'secret': {u'secretName': u'aws-secret'}, u'name': u'aws-secret'}, {u'name': u'kaniko-test-cm', u'projected': {u'sources': [{u'configMap': {u'name': u'kaniko-test-cm-docker'}}, {u'configMap': {u'name': u'kaniko-test-cm-jenkins'}}]}}], u'containers': [{u'image': u'gcr.io/kaniko-project/executor:latest', u'args': [u'--dockerfile=./Dockerfile', u'--context=/kaniko-test-cm', u'--destination=xxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/jenkins-test/jenkins-test:v1.0.0'], u'volumeMounts': [{u'readOnly': True, u'mountPath': u'/root/.aws', u'name': u'aws-secret'}, {u'readOnly': True, u'mountPath': u'/kaniko-test-cm', u'name': u'kaniko-test-cm'}], u'name': u'kaniko'}]}, u'apiVersion': u'v1', u'metadata': {u'namespace': u'ansible-test', u'name': u'kaniko'}}])
PLAY RECAP *************************************************************************************************************
localhost : ok=9 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
コンソールからECRにイメージがプッシュされたことが確認できます。
注意
issuesやプルリクから察するに、メンテナンスはあまり活発に行われていないように思います。
また、最近のissuesの中にはマルチステージビルドに失敗する等、クリティカルな内容の物も見受けられます。
もし技術選定に関われる立場にあるなら、できる限りKanikoは使用しない設計に倒した方が無難でしょう。