git pushでkubernetesのpodのイメージ更新まで自動化出来たので手順を残します。

2024年2月4日

How To Automate Deployments to DigitalOcean Kubernetes with CircleCI

githubに公開しました。

https://github.com/a5ro5a/k8s-deploy-with-circleci-ecr


  • 実現したいこと
    • git push したタイミングでcircleciでテスト、問題なければkubernetes上で稼働しているpodのイメージを更新させる

environment

  • kubernetes
    • v1.28.2
  • namespace
    • doks-wp
  • container registry
    • ECR private
  • 既にdigitalocean上のkubernetesにて運用中である
  • deploy
    • kubernetesへはyamlファイルの管理はしない
    • podのイメージの更新のみとする

SSH 鍵の作成

非対称型暗号化のSSH鍵のペアをローカル環境で作成

  • 秘密鍵はcircleciのプロジェクトに
  • 公開鍵はgithubのアカウントに

空のgitレポジトリを作成しておく

  • レポジトリの作成
  • SSHの公開鍵の登録

circle ciにてプロジェクトを作成する

https://circleci.com/docs/ja/create-project/

  • github.comを選択

  • SSH秘密鍵を登録

  • Faster: Commit a starter CI pipeline to a new branch オプションを選択します。これにより、プロジェクト用の新しい circleci-project-setup ブランチが作成されます。

circle ciからkubernetesを操作するアカウントの作成

こちらに手順記載しています

circle ciプロジェクト設定

Projects > プロジェクト選択 > 右側歯車 Project Settings

Environment Variables

環境変数の追加

Name Value
AWS_ACCESS_KEY_ID AWS API ID
AWS_ACCOUNT_ID AWS Account ID
AWS_DEFAULT_REGION ECRコンテナレジストリリージョン
AWS_SECRET_ACCESS_KEY AWS API キー
DEPLOYMENT_NAME kubernetesのdeployementの名前
ECR_IMAGE_NAME ECRコンテナレポジトリ名
KUBERNETES_TOKEN 先に$TOKENとして取得したもの
KUBERNETES_SERVER 先に$KUBERNETES_SERVERとして取得したもの(~/.kube/config に記載されているserver: の値)
KUBERNETES_CLUSTER_CERTIFICATE ~/.kube/config に記載されているcertificate-authority-data: の値

circleciのmanifest作成

cd ~/work/$_PROJECTNAME
mkdir .circleci
vi .circleci/config.yml
version: '2.1'
orbs:
  aws-cli: circleci/[email protected]

jobs:
  build:
    working_directory: ~/app
    docker: 
      - image: cimg/python:3.9
    steps:
      - checkout
      - setup_remote_docker
      - aws-cli/install
      - aws-cli/setup
      - run:
          name: docker build
          command: |
            source ~/app/.env
            docker build -t ${ECR_IMAGE_NAME}:${_VERSION} ~/app/docker
            status=$(echo "$?")
            if [ "${status}" != "0" ]; then
              exit 1
            else
              RESISTRY_URL=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com
              REPOSITORY_URL=${RESISTRY_URL}/${ECR_IMAGE_NAME}
              aws ecr get-login-password --region ${AWS_DEFAULT_REGION} | docker login --username AWS --password-stdin $RESISTRY_URL
              #docker tag ${ECR_IMAGE_NAME}:${_VERSION} ${REPOSITORY_URL}:${_VERSION}
              docker tag docker.io/library/${ECR_IMAGE_NAME}:${_VERSION} ${REPOSITORY_URL}:${_VERSION}
              docker push ${REPOSITORY_URL}:${_VERSION}
            fi
            exit 0

  deploy:
    docker:
      #- image: circleci/buildpack-deps:bullseye
      - image: cimg/python:3.9
    working_directory: ~/app
    steps:
      - checkout
      - run:
          name: Install envsubst
          command: |
            sudo apt-get update && sudo apt-get -y install gettext-base
      - run:
          name: Install awscli
          command: |
             curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
             unzip awscliv2.zip
             sudo ./aws/install
      - run:
          name: Install kubectl
          command: |
            curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
            chmod u+x ./kubectl
      - run:
          name: Deploy Code
          command: ./scripts/ci-deploy.sh

workflows:
  version: 2
  build-deploy-master:
    jobs:
      - build:
          filters:
            branches:
              only: master
      - deploy:
          requires:
            - build
          filters:
            branches:
              only: master
mkdir scripts
vi scripts/ci-deploy.sh
chmod +x scripts/ci-deploy.sh
#! /bin/bash -x
# exit script when any command ran here returns with non-zero exit code
set -e

#COMMIT_SHA1=$CIRCLE_SHA1

source ~/app/.env

# Export it so it's available for envsubst
#export COMMIT_SHA1=$COMMIT_SHA1

#  Since the only way for envsubst to work on files is using input/output redirection,
#  it's not possible to do in-place substitution, so you will save the output to another file
#  and overwrite the original with that one.
#envsubst <./kube/do-sample-deployment.yml >./kube/do-sample-deployment.yml.out
#mv ./kube/do-sample-deployment.yml.out ./kube/do-sample-deployment.yml

echo "$KUBERNETES_CLUSTER_CERTIFICATE" | base64 --decode > cert.crt

RESISTRY_URL=${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com
REPOSITORY_URL=${RESISTRY_URL}/${ECR_IMAGE_NAME}

aws ecr get-login-password --region ${AWS_DEFAULT_REGION} | docker login --username AWS --password-stdin $RESISTRY_URL

./kubectl \
  --kubeconfig=/dev/null \
  --server=$KUBERNETES_SERVER \
  --certificate-authority=cert.crt \
  --token=$KUBERNETES_TOKEN \
  set image deployment/${DEPLOYMENT_NAME} -n ${ECR_IMAGE_NAME} ${ECR_IMAGE_NAME}=${REPOSITORY_URL}:${_VERSION}
chmod +x scripts/ci-deploy.sh

説明

  • buildジョブ
    • タグ名が$CIRCLE_SHA1 となり長くてわかりずらい為、自分で指定できるように変更(.envファイル)
      • ../.envファイルを読み込み_VERSION情報を取得します(イメージのタグ名)
    • buildして問題なければECRへ認証し、タグ付けし、PUSHします。
    • タグ付けの際に、"docker.io/library/"が無いとPUSHがタイムアウトで失敗します。
  • deployジョブ
    • buildが成功したときのみ実行
    • masterブランチへのpush時のみ実行
    • kubectlでdeploymentへset imageするだけです
    • yamlファイルを用意してkubectl apply -f でも利用可能

gitへpush

含まれるもの

  • .circleci/config.yml
  • scripts/ci-deploy.sh
  • .envファイル
  • docker/Dockerfile
  • その他docker buildに必要なもの

確認

Circle CI

ECR

kubernetes

ocarina@ab350-pro4:~/work/doks-wp$ kubectl get pods -n doks-wp
NAME                                READY   STATUS    RESTARTS   AGE
doks-wp-dev-web-776d445c4c-sdfkx    1/1     Running   0          55m
doks-wp-prod-web-55dc67dc98-75584   1/1     Running   0          54s
doks-wp-prod-web-55dc67dc98-xx5pd   1/1     Running   0          51s

ocarina@ab350-pro4:~/work/doks-wp$ kubectl describe pods/doks-wp-prod-web-55dc67dc98-xx5pd -n doks-wp | grep Image\: 
    Image:          123456789012.dkr.ecr.ap-southeast-1.amazonaws.com/doks-wp:0.0.13
ocarina@ab350-pro4:~/work/doks-wp$ 

0.0.13に更新されたことを確認出来ました。

参考
https://www.digitalocean.com/community/tutorials/how-to-automate-deployments-to-digitalocean-kubernetes-with-circleci

Posted by ocarina