Golangを用いたマニフェスト(Kubernetes)生成ツール
注意事項
本記事ではgolangで実装したコマンドラインツールの紹介をしますが,私が構築したKubernetes環境に最適化(スペックの選択等)させているため,そのままでは使用することはできません.使用される際は自己責任でコードを書き換えて使用してください.
はじめに
本ブログではKubernetes(以下k8s) Clusterの整備に関する備忘録をまとめてきました.(最近更新できてない分は少しづつ更新していきます.)
現在はおおよそ図1のような構成でJupyterlabを提供することにより,機械学習環境をk8sを用いて構築しています.
しかしながら,k8sを何も知らない人にとってはマニフェストの作成が使用への大きな壁になっていました.また,マニフェストのサンプルを配布した場合でも,スペックの異なるノードをまとめて運用しているためコンテナのスペックを選択する際に各ノードのスペックを知っておく必要があり,よりマニフェストの作成が複雑になっていました.
そこで今回,以下図2の赤枠部分を自動化するコマンドラインツールcksctlをgolangで実装してみました.使用方法などはGitLabのReadmeに書いてあるので,どんな感じで設計したのかをまとめておきたいと思います.
前提条件
図2のフローはGitOpsという思想に基づいたものになっています.GitOpsをざっくりいうと設定ファイル(k8sでいう所のマニフェスト)やプログラムファイルをGitで管理し,CIやCDをGitを起点に行おうというものです.図2をみて貰えばわかりますが,k8sを使用する場合,CIツールとCDツールを分離して従来のようなCIツールに権限が集中する状況を避けます.また,マニフェストを人間が管理し,kubectlコマンドを用いてアプリケーションのデプロイを行っているとマニフェストの管理が杜撰になり,デプロイミスも増えてしまいます.そこで,マニフェストをGit管理することでマニフェストの変更履歴を残し,CDツールでデプロイすることにより,オペレーションエラーを極力減らす事ができます.
ツールの選択
今回の環境では,アプリケーションの開発を行うわけではないため,CIはあまり使用しません.そのためCIを行うのは,Dockerfileのpushによるdocker buildのみになります.
CIツールにはGitLab CI,CDツールにはArgoCDを採用します.
環境
今回アプリケーションの開発も実際にアプリケーションを動作させる環境もDockerを用いて作成しました.これにより,開発環境と実行環境を揃える事ができ,さらにアプリケーションを使用する際もdocker runするだけで動作させる事ができます.
開発環境
FROM golang:1.13.10 LABEL maintainer="CVLAB.KubernetesService:tenzen" ENV USER_NAME tenzen ENV UID 1000 RUN useradd -m -u ${UID} ${USER_NAME} ENV ARGO_CLI_VERSION v1.5.5 ENV CGO_ENABLED=0 ENV GOOS=linux ENV GOARCH=amd64 ENV GOPATH /home/${USER_NAME}/app WORKDIR ${GOPATH}/src RUN go get -u gopkg.in/src-d/go-git.v4/... \ && go get gopkg.in/yaml.v3 \ && curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/${ARGO_CLI_VERSION}/argocd-linux-amd64 \ && chmod +x /usr/local/bin/argocd
実行環境
アプリケーションの実行環境では,開発環境でビルドした後のバイナリファイルのみを実行環境に持ってくるマルチステージビルドを行う事で,イメージ容量の軽減を実現しています.実際に開発環境のイメージは1GBほどありますが,アプリケーション環境は20MBほどにおさまっています.
FROM golang:1.13.10 as builder LABEL maintainer="CVLAB.KubernetesService:tenzen" ENV USER_NAME builder ENV UID 1000 RUN useradd -m -u ${UID} ${USER_NAME} ENV CGO_ENABLED=0 ENV GOOS=linux ENV GOARCH=amd64 ENV GOPATH /home/${USER_NAME}/app WORKDIR ${GOPATH}/src RUN go get -u gopkg.in/src-d/go-git.v4/... \ && go get gopkg.in/yaml.v3 \ && chown -R ${UID}:${UID} . COPY ["builder", "."] USER ${USER_NAME} RUN go build -o cksctl main.go FROM alpine:3.9.6 ENV BUILDER_NAME builder ENV USER_NAME user ENV UID 1000 RUN adduser -D -g '' --uid ${UID} ${USER_NAME} ENV BUILD_DIR /home/${BUILDER_NAME}/app/src ENV HOME_DIR /home/${USER_NAME}/app WORKDIR ${HOME_DIR} COPY --from=builder ["${BUILD_DIR}/cksctl", "."] COPY --from=builder ["${BUILD_DIR}/YamlTemplates", "YamlTemplates"] RUN apk update \ && apk add curl \ && curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/v1.5.5/argocd-linux-amd64 \ && chmod +x /usr/local/bin/argocd \ && mkdir cksSettingFiles \ && chown -R ${UID}:${UID} . USER ${USER_NAME} ENTRYPOINT [ "./cksctl" ]
実装
Jupyterlabをデプロイするまでの大きな流れとしては,
となっています.
GitLab CI
1のGitLab CIで使用するgitlab-ci.ymlはサンプルを参考に以下のようなものを作成しました.
docker-build-master: image: docker:latest stage: build services: - docker:dind before_script: - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY script: - docker build --pull -t "$CI_REGISTRY_IMAGE" . - docker push "$CI_REGISTRY_IMAGE" only: - master
この設定ファイルを使用することによりDockerfileをpushすると自動的にコンテナイメージのビルドが始まります.
cksctl
2においてはユーザに入力された要求スペック情報などを元にHelm Chartのvalues.yamlを作成し,HelmChartとともにGit リポジトリにプッシュします. 例えばjupyterlabのvalues.yamlは以下のようになっており,golangのtext/templateを用いて値を書き込みます.
uname: {{ .uname }} jupyter_pass: {{ .jupyter_pass }} image_name: {{ .image_name }} hardware_type: {{ .hardware_type }} image_secret: {{ .image_secret }} gpu_flag: {{ .gpu_flag }} gpu_type: {{ .gpu_type }} gpu_num: {{ .gpu_num }} cpu_num: {{ .cpu_num }} memory_capacities: {{ .memory_capacities }} created_day: {{ .created_day }}
また,一度入力した情報を設定ファイルとして保存し,使用できるようにもなっています. 設定ファイルは以下のようになっており,values.yamlと同様にgolangのtext/templateを用いて書き込みます.
settings: - name: {{ .cks_proj_name }} metadata: - git: - uname: {{ .account_name }} token: {{ .access_token }} project: {{ .project_name }} type: {{ .git_type }} k8s: - basic_info: - uname: {{ .uname }} jupyter_pass: {{ .jupyter_pass }} image: {{ .image_name }} secret: {{ .image_secret }} spec: - gpu: - flag: true hardware: {{ .hardware_type }} {{- if eq .gpu_flag "true" }} type: {{ .gpu_type }} num: {{ .gpu_num }} {{- end }} cpu: - num: {{ .cpu_num }} memory: - capacities: {{ .memory_capacities }} cephfs: - capacities: {{ .cephfs_capacities }}
ArgoCD
3では,ArgoCDがHelmChartを用いてjupyterをデプロイします. HelmChartを使用しているので,HelmChartを準備し,values.yamlをgolangのtext/templateにのとった形式に変更すれば簡単に対応アプリケーションを 増やせるようになっています.
改善点
現状Gitのマスターブランチにしかpushできないので,別ブランチにもpushできるようにしていきたいと考えています.
最後に
今回初めてgolangを使ったのですが,はじめはJavaの知識が邪魔をして構造体やインターフェースを理解する事が大変でした.普段全くアプリケーション開発などしないため相当ひどいコードになっていると思うので,コードを見て発狂する可能性のある方は見ないことをお勧めします.