kurobato.hateblo.jp
前回はDockerfileのリポジトリを更新すると自動ビルドされたコンテナイメージがdocker hubにプッシュされる環境を用意しました。
次は、Argo CDというツールを使って、k8sマニフェストのリポジトリを更新すると自動でコンテナがデプロイされる環境を構築します。
Argo CDインストール
argocdネームスペースを作成してminikube k8s上にargoCDをインストールします。
#k8sロードバランサの用意(argocd-serverへアクセス用) #minikubeで提供されるtunnelを起動します。 $ minikube tunnel Status: machine: minikube pid: 4324 route: 10.96.0.0/12 -> 192.168.99.100 minikube: Running services: [argocd-server, gitops-service, istio-ingressgateway] #k8s node確認 $ kubectl get nodes -o wide NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME minikube Ready control-plane,master 11d v1.21.2 192.168.99.100Buildroot 2020.02.12 4.19.182 docker://20.10.6 minikube-m02 Ready 136m v1.21.2 192.168.99.101 Buildroot 2020.02.12 4.19.182 docker://20.10.6 minikube-m03 Ready 135m v1.21.2 192.168.99.102 Buildroot 2020.02.12 4.19.182 docker://20.10.6 #argocdのインストール $ kubectl create namespace argocd $ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
ポッドの確認
いろいろポッドがデプロイされています。
argocd-serverがユーザアクセス用のサーバみたいです。
$ kubectl get pod -n argocd NAME READY STATUS RESTARTS AGE argocd-application-controller-0 1/1 Running 0 10m argocd-dex-server-68c7bf5fdd-flk9c 1/1 Running 0 10m argocd-redis-7547547c4f-pcmlk 1/1 Running 0 10m argocd-repo-server-58f87478b8-lhg78 1/1 Running 0 10m argocd-server-6f4fcdc5dc-bpmgc 1/1 Running 0 10m
サービスの確認
argocd-serverはデフォルトでは外部公開されていません。
argocd-serverに接続できるようにサービスタイプをLoadBalancerに変更します。
$ kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
$ kubectl get services -n argocd NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE argocd-dex-server ClusterIP 10.98.145.535556/TCP,5557/TCP,5558/TCP 3h5m argocd-metrics ClusterIP 10.110.187.11 8082/TCP 3h5m argocd-redis ClusterIP 10.96.238.136 6379/TCP 3h5m argocd-repo-server ClusterIP 10.107.230.1 8081/TCP,8084/TCP 3h5m argocd-server LoadBalancer 10.107.71.74 10.107.71.74 80:30364/TCP,443:32221/TCP 3h5m argocd-server-metrics ClusterIP 10.107.149.9 8083/TCP 3h5m
これでargocd-serverサービス経由でargocd-serverポッドにアクセスできます。
CLIのダウンロード
sudo curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64 sudo chmod +x /usr/local/bin/argocd
argocd-server へのアクセス
10.107.71.74:80にアクセスします。
初期パスワードの確認(初期ユーザはadmin)
$ kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d && echo
XXnTZyfLjyehwude
リポジトリ登録
k8sマニフェストのあるリポジトリをargocdに登録します。
k8sにデプロイするサンプルアプリとサービス
Hello GitOps!を返すwebサーバコンテナをk8sのdeployment podとしてデプロイし、ロードバランサで公開します。
package main import ( "fmt" "net/http" ) func handler(w http.ResponseWriter, r *http.Request){ fmt.Fprintf(w,"Hello GitOps!!") } func main(){ http.HandleFunc("/",handler) http.ListenAndServe(":8080",nil) }
# Stage-1 FROM golang:1.16 as builder COPY ./app/main.go ./ RUN go build -o /gitops-go-app ./main.go # Satge-2 FROM ubuntu EXPOSE 8080 COPY --from=builder /gitops-go-app /. ENTRYPOINT ["./gitops-go-app"]
apiVersion: apps/v1 kind: Deployment metadata: name: gitops-deployment spec: replicas: 3 selector: matchLabels: app: gitops template: metadata: labels: app: gitops spec: containers: - name: gitops image: docker.io/l3j5g7d9/gitops-go-app:latest imagePullPolicy: IfNotPresent
apiVersion: v1 kind: Service metadata: name: gitops-service spec: type: LoadBalancer ports: - name: gitops protocol: TCP port: 80 targetPort: 8080 selector: app: gitops
マニフェストが認識されました。
手動同期
設定が手動同期になっているため、同期ボタンをポチります。
すると、deployment podが展開されたような表示になります。
k8s上で動いているか確認します。
$ kubectl get pods -n default NAME READY STATUS RESTARTS AGE gitops-deployment-64879cfb89-n48hc 2/2 Running 0 21m gitops-deployment-64879cfb89-q878s 2/2 Running 0 21m gitops-deployment-64879cfb89-v58gk 2/2 Running 0 21m $ kubectl get services -n default NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE gitops-service LoadBalancer 10.106.186.67 10.106.186.67 80:32018/TCP 2m45s kubernetes ClusterIP 10.96.0.1443/TCP 11d $ curl 10.106.186.67:80 Hello GitOps!!
ポッドとサービスが作成され、ロードバランサ経由でwebサーバにアクセスできています。
自動同期
次は自動同期を有効化します。これでk8sリポジトリを変更すると自動検出してk8sにデプロイしてくれるようになるっぽいです。
すると、argoとk8s上で変更内容が自動反映されました。
$ kubectl get pods -n default NAME READY STATUS RESTARTS AGE gitops-deployment-changed-64879cfb89-q2gnj 2/2 Running 0 5m21s gitops-deployment-changed-64879cfb89-rk6cn 2/2 Running 0 5m21s gitops-deployment-changed-64879cfb89-trjn9 2/2 Running 0 5m21s $ kubectl get services -n default NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE gitops-service LoadBalancer 10.106.186.67 10.106.186.67 80:32018/TCP 43m kubernetes ClusterIP 10.96.0.1443/TCP 11d $ curl 10.106.186.67:80 Hello GitOps!!
これにてCD完成です。GUIポチポチできるので楽ちんですね。
CICDパイプラインの作成
ここまでGithub Actions(CI)とArgo CD(CD)の環境を構築してきました。
最後にこれらを統合してCICDパイプラインにします。
つまり、アプリケーションのソースコードとDockerfileをリポジトリにプッシュするとビルドからデプロイまで全自動で行われるようにします。
1.Github Actions:Dockerfileのリポジトリ更新をトリガとして自動ビルド+コンテナイメージのプッシュ
2.Argo CD:k8sマニフェストのリポジトリ更新をトリガとして自動デプロイ
方法としては、Github Actionsの処理でk8sマニフェストのリポジトリを更新する処理を加えることでArgo CDの同期処理が起動するようにします。
処理としてはapp.yamlのポッド名をgitops-deployment[デプロイ番号]に書き換えてプッシュするだけです。
実際には、Helmも組み込んでKubernetesマニフェストを管理するのが無難っぽいのですが、少しややこしくなるので今回は省きます。
余談ですがyqコマンドなんてあったんですね。最近インフラレイヤはyamlだらけなので重宝しそうです。
code/.github/workflows$ nano main.yml name: Github Action CI on: push: branches: [ main ] jobs: build: name: GitOps Workflow runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v2 #Buildkitによるイメージビルド - name: Build an image from Dockerfile run: | DOCKER_BUILDKIT=1 docker image build . -f app/Dockerfile --tag ${{ secrets.DOCKERUSER }}/gitops-go-app:latest #Trivyによるイメージスキャン - name: Run Trivy uses: aquasecurity/trivy-action@master with: image-ref: '${{ secrets.DOCKERUSER }}/gitops-go-app:latest' format: 'table' exit-code: '1' ignore-unfixed: true severity: 'CRITICAL,HIGH' #DockerHubにイメージプッシュ - name: Push Image run: | docker login docker.io --username ${{ secrets.DOCKERUSER }} --password ${{ secrets.DOCKERPASSWORD }} docker image push ${{ secrets.DOCKERUSER }}/gitops-go-app:latest #Kubernetesマニフェストの更新 - name: Change Pod Name run: | echo -e "machine github.com\nlogin ${{ secrets.GITHUBUSER }}\npassword ${{ secrets.GITHUBTOKEN }}" > ~/.netrc git config --global user.email ${{ secrets.EMAIL }} git config --global user.name ${{ secrets.GITHUBUSER }} git clone https://github.com/${{ secrets.GITHUBUSER }}/config.git cd config/manifest yq e '.metadata.name = "gitops-deployment${{ github.run_number }}"' -i app.yaml git add app.yaml git commit -m ${{ github.run_number }} -a git push origin main
Github Actionsのワークフロー完了後にリポジトリのapp.yamlを確認するとポッドラベルが更新されています。
次にArgo CDのコンソールを確認すると、更新されたポッド名が反映されています。
k8sでもちゃんと動いています。
$ kubectl get pods -n default NAME READY STATUS RESTARTS AGE gitops-deployment31-64879cfb89-6ds4x 2/2 Running 0 24m gitops-deployment31-64879cfb89-hfhh2 2/2 Running 0 24m gitops-deployment31-64879cfb89-tmlf9 2/2 Running 0 24m $ kubectl get services -n default NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE gitops-service LoadBalancer 10.106.186.67 10.106.186.67 80:32018/TCP 6h31m kubernetes ClusterIP 10.96.0.1443/TCP 12d $ curl 10.106.186.67:80 Hello GitOps!!
これでCICDパイプラインの完成です。
とりあえず動いたので満足。