【AWS】ansibleでECRにDockerイメージをpushして、EKS環境にデプロイする
目的
前提条件
- 作業する環境に
Python
とAnsible
、kubectl
のインストールが必要 aws eks update-kubeconfig ...
でconfigが作成済み
# Ansibleのk8sモジュールを使用する際に必要なライブラリ
$ pip install pyyaml kubernetes openshift
参考
こちらの記事を参考にEKS環境を構築しました。
変更点は以下となります。
- 社用アカウントのVPC数が上限に達していたので、
CloudFormation
によるデプロイはせず、既存のVPCを利用 - addonのコンテナを起動するとセカンダリIPが不足するので、ノードグループのインスタンスタイプを
t3.medium
に変更- 使用しないときはAutoScalingのノード数を
0
に設定すると、ノードが停止します
- 使用しないときはAutoScalingのノード数を
構成図
ディレクトリ構成
とりあえず、必要最低限のファイルを用意しました。
ディレクトリ構成について、公式がベストプラクティスを定義していますので、そちらが参考になります。
. ├── local.yml # site.yml から呼び出されて実行されるファイル ├── site.yml # 本YAMLファイルから、[任意の処理名].ymlを呼び出す。 ├── Dockerfile # pushするDockerイメージ ├── inventory # ホストとそれに紐づく変数を定義するファイル │ └── hosts └── roles # Playbookのタスクetc...を格納。詳細は公式ドキュメント参照。 ├── ... └── k8-jenkins # role毎にディレクトリを用意すると良さそう。 └── tasks ├── deployment.yml # EKSへデプロイするマニフェスト。 └── main.yml # Dockerイメージのビルドやpush等の実処理を記載するファイル。
実装
site.yml
実行ファイルをインポート。
--- - import_playbook: local.yml
local.yml
実行対象のroleをroles
の配列に含める。
ansible.kubernetes-modules
はk8sデプロイモジュールを利用する際に必要になります。
先にインストール済みの環境であれば、不要かも?
--- - name: Ansible Test hosts: local roles: - ansible.kubernetes-modules - k8s
inventory/hosts
ローカル環境の定義のみ記載しています。
ベストプラクティスによると、変数定義はgroup_vars
やhost_vars
ディレクトリに纏めて配置するようです。
クレデンシャル管理はPJの方針に従ってください。
また、最初はinventories
という名前のディレクトリにしていたのですが、--syntax-chek
実行時に警告?が出ていたので、とりあえずinventory
としています。
[local] localhost ansible_connection=local [local:vars] region=ap-northeast-1 key_id=xxxxxxxx access_key=xxxxxxxx image_name=jenkins-test/jenkins-test image_version=v1.0.0
roles/k8s/tasks/main.yml
AWSコマンドを使用する為、configなどの配置も併せて行っています。
埋め込み文字は Jinja2 構文 で変数が展開されます。
--- - name: "Push Docker image to AWS ECR" debug: "Push Docker image to AWS ECR" - name: Make aws directory file: dest: ~/.aws state: directory mode: u=rwx,g=o= - name: Copy aws config template: src: aws/config dest: ~/.aws/config mode: u=rw,g=o= - name: Copy aws credentitals template: src: aws/credentitals dest: ~/.aws/credentitals mode: u=rw,g=o= - name: Install docker-py for build Docker pip: name: docker-py state: present - name: Build Docker image docker_image: build: path: ./ name: "{{ image_name }}" tag: "{{ image_version }}" - name: Docker login shell: "aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin <ユーザーID>.dkr.ecr.ap-northeast-1.amazonaws.com" args: executable: /bin/bash - name: Install boto3 pip: name: boto3 state: present - name: Create repository ecs_ecr: name: "{{ image_name }}" aws_access_key: "{{ key_id }}" aws_secret_key: "{{ access_key }}" region: "{{ region }}" register: ecr_repo - name: Add tag docker_image: name: "{{ image_name }}:{{ image_version }}" repository: "{{ ecr_repo.repository.repositoryUri }}" tag: "{{ image_version }}" - name: Push image to ECR docker_image: name: "{{ ecr_repo.repository.repositoryUri }}:{{ image_version }}" push: yes - name: Create deployment to EKS vars: imagename: "{{ ecr_repo.repository.repositoryUri }}:{{ image_version }}" replica: 1 namespace: ansible-test k8s: definition: '{{ item }}' kubeconfig: ~/.kube/config state: present loop: - "{{ lookup('template', 'deployment.yml') | from_yaml_all | list }}"
roles/k8s/tasks/deployment.yml
EKSへデプロイするマニフェストファイル。
ジョブで定義したvars
の各値がマニフェストの埋め込み文字に反映されます。
apiVersion: apps/v1 kind: Deployment metadata: name: test-jenkins-app namespace: {{ namespace }} spec: replicas: {{ replica }} selector: matchLabels: app: test-jenkins-app minReadySeconds: 10 template: metadata: labels: app: test-jenkins-app spec: volumes: - name: git-secret-volume secret: secretName: git-secret containers: - image: {{ imagename }} name: jenkins-test-container restartPolicy: Always ports: - containerPort: 8080 resources: requests: cpu: 200m memory: 20Mi limits: cpu: 512m memory: 500Mi volumeMounts: - name: git-secret-volume mountPath: /var/jenkins_home/.ssh readOnly: true --- apiVersion: v1 kind: Service metadata: name: test-jenkins-service namespace: {{ namespace }} labels: app: test-jenkins-service spec: type: LoadBakancer ports: - port: 80 protocol: TCP targetPort: 8080 selector: app: test-jenkins-app
Dockerfile
とりあえずJenkins
を動かしてみます。
FROM jenkins/jenkins:latest RUN mkdir -p /var/jenkins_home/.ssh && ¥ chown -R jenkins:jenkins /var/jenkins_home COPY --chown=jenkins:jenkins ./Jenkinsfile ./
playbook実行
各ジョブが正常終了することを確認。
$ ansible-playbook site.yml -i inventory/hosts PLAY [Ansible Test] ******************************************************************************************************************** TASK [Gathering Facts] ***************************************************************************************************************** [WARNING]: Platform linux on host localhost is using the discovered Python interpreter at /usr/bin/python, but future installation of another Python interpreter could change this. See https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more information. ok: [localhost] TASK [ansible.kubernetes-modules : Install latest openshift client] ******************************************************************** skipping: [localhost] TASK [k8s : push docker image to ECR & deploy to EKS] ****************************************************************************** ok: [localhost] => { "msg": "push docker image to AWS ECR & deploy to EKS" } TASK [k8s : make aws directory] ******************************************************************************************************** ok: [localhost] TASK [k8s : copy aws config] *********************************************************************************************************** ok: [localhost] TASK [k8s : copy aws credentials] ****************************************************************************************************** ok: [localhost] TASK [k8s : install docker-py for build docker] **************************************************************************************** ok: [localhost] TASK [k8s : build docker image] ******************************************************************************************************** [WARNING]: The value of the "source" option was determined to be "build". Please set the "source" option explicitly. Autodetection will be removed in Ansible 2.12. ok: [localhost] TASK [k8s : docker login] ************************************************************************************************************** changed: [localhost] TASK [k8s : install boto3] ************************************************************************************************************* ok: [localhost] TASK [k8s : create repository] ********************************************************************************************************* ok: [localhost] TASK [k8s : add tag] ******************************************************************************************************************* [WARNING]: The value of the "source" option was determined to be "pull". Please set the "source" option explicitly. Autodetection will be removed in Ansible 2.12. ok: [localhost] TASK [k8s : push image to ecr] ********************************************************************************************************* ok: [localhost] TASK [k8s : Create a Deployment to EKS] ************************************************************************************************ ok: [localhost] => (item=[{u'kind': u'Deployment', u'spec': {u'selector': {u'matchLabels': {u'app': u'test-jenkins-app'}}, u'minReadySeconds': 10, .... u'spec': {u'type': u'LoadBalancer', u'ports': [{u'targetPort': 8080, u'protocol': u'TCP', u'port': 80}], u'selector': {u'app': u'test-jenkins-app'}}, u'apiVersion': u'v1', u'metadata': {u'labels': {u'app': u'test-jenkins-service'}, u'namespace': u'ansible-test', u'name': u'test-jenkins-service'}}]) PLAY RECAP ***************************************************************************************************************************** localhost : ok=13 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
コンテナの起動確認
参考サイトや公式ドキュメントの手順通りに設定していれば、IAMの設定はできていると思います。
$ alias k=kubectl $ k get pod --namespace ansible-test NAME READY STATUS RESTARTS AGE test-jenkins-app-7c7ffcfb46-fq5q6 1/1 Running 0 46m # コンテナにログインして、jenkinsのinitialAdminPasswordを確認 $ k exec -it test-jenkins-app-7c7ffcfb46-fq5q6 -n ansible-test -- /bin/bash jenkins@test-jenkins-app-7c7ffcfb46-fq5q6:/$ cat /var/jenkins_home/secrets/initialAdminPassword xxxxxxxxxxxxxxxxxxxxxxxxxxx jenkins@test-jenkins-app-7c7ffcfb46-fq5q6:/$ exit exit # アクセス先を確認 $ k get service --namespace ansible-test NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE test-jenkins-service LoadBalancer 10.100.138.217 ac7d2f38812bc41d7bf81a39a4a7c467-1945438877.ap-northeast-1.elb.amazonaws.com 80:32108/TCP 3d17h
http://<EXTERNAL-IP>
にアクセスすると、jenkinsの初期画面が表示される。
HTTPS接続にしたい場合、ACMで証明書を作成すると良いでしょう。