chroju.dev/blog

the world as code

kops と Argo CD でプライベート Kubernetes を建てる

先日 CloudNative Days Tokyo 2021 を見ていて、知らない kubernetes 関連のツールがまだまだあることを実感した。 AWS サービスや各種 OSS はわりとサクッとローカルで試せたりもするんだけど、 k8s 関係もプライベートでシュッと試せる環境が欲しいよな、ということを考え、クラスターを1個作ってみた。

利用技術

Kubernetes のインストールには kOps を使った。

そのほかのツールとしては kubeadmkubespray などがある。 kubeadm は以前使ったこともあるのだが、サーバーの中でコマンドを実行することで Kubernetes コントロールプレーンもしくはワーカーノードとして必要な設定が施される。 kops はこれとは異なり、 AWS で必要なリソース各種の構築と、サーバー内の設定の双方をおこなってくれる。今回 kops を選んだのは、 Kubernetes Cluster 一式が一発で構築できるので kubeadm より楽だったから、という理由に尽きる。VPS を使うより AWS のほうがある程度金額面で高くはなるが、検証するなら業務でもよく使う環境のほうがいいだろうということで AWS にした。リザーブドインスタンスを適用すれば、サーバー代自体はそこまで国内主要 VPS と変わらないと認識している。

ちなみに kubespray のことはよく知らない。

また、 Kubernetes 上に manifest を適用するにあたっては Argo CD による GitOps を採用した。これは業務で使っているものに揃えた。

kops

kops は本当にザックリでよければ、 kops create cluster $NAME コマンドで初期設定を作成し、 kops update cluster $NAME --yes でクラスターの構築が終わる。構築にあたっては ~/.kube/config も自動で設定され、そのまま k8s が利用可能となる。もともと AWS で簡単にクラスターを立てることを目的としたツールだったようだが、現在はその他の各種クラウドサービス、 VPS も alpha, beta の状態でサポートされている。

kops の設定情報は create cluster コマンドにオプションで手渡す。例えば --master-size でコントロールプレーンのインスタンスタイプを設定できる。設定情報の実態は、 kops コマンドの実行時に予め KOPS_STATE_STORE 環境変数で設定した S3 バケットに保存される。

kops + Terraform

設定を宣言的に Git で管理したければ、 create cluster コマンドに --target=terraform オプションを与えることで、 Terraform の設定を出力させることができる。

$ kops create cluster kops.chroju.dev --zones=ap-northeast-1a --master-size t3.small --node-size t3.small --networking calico --ssh-public-key ~/.ssh/id_rsa.pub --out=. --target=terraform

$ terraform apply -auto-approve

これは先の S3 バケット内の設定を Terraform 形式に落とし込む形になるが、この後は S3 側の設定は必要としなくなり、 Terraform コマンドだけでオペレーションできるようになる。このほうが、 kops はあくまで設定テンプレートを出力するだけのツールとして扱うことができ、クラスター管理において kops を離れることができるという点でも利がある(ただし、 kops が自動的に etcd のバックアップなどでも S3 を使用するため、 S3 が不要になるわけではない)。

ssh 接続を ssm に切り替える

kops はデフォルトで ssh による各ノードへのアクセスを有効としているが、セキュアではないので AWS SSM による接続へ切り替えたい。 Terraform を編集して ssh の許可を塞ぎ、各ノードの IAM Role に AmazonEC2RoleforSSM policy を追加しておく。

Image from Gyazo

Image from Gyazo

画像は省略したが、 IPv6 の Port 22 も同様に閉じておく。

ノード内部設定変更の反映

kops が出力する Terraform では、各ノード内部の設定には user data を使用している。 Terraform では user data を編集してもインスタンスの再起動は行われないため、即時の反映はされない。この場合は kops rolling-update を実行することで、インスタンスを入れ替えることができる。

Argo CD

2021年2月から、公式の Helm Chart がリリースされているので、これを使ってインストールした。

App of apps

Argo CD による Application の管理には App of apps パターンを採用した。

Argo CD は、管理対象の Kubernetes manifests を Application と呼ばれる CRD で設定する。対象の Git レポジトリの URL やパスを Application 内で設定することで、定期的にそのレポジトリを fetch して、 Kubernetes クラスター上に apply する。

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: guestbook
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/argoproj/argocd-example-apps.git
    targetRevision: HEAD
    path: guestbook
  destination:
    server: https://kubernetes.default.svc
    namespace: guestbook

この Application 自体も Kubernetes resource なので、 Argo CD で管理したくなる。そこで Application を管理する Application(便宜的に「親 app」と呼ぶ)を作成するパターンが App of apps と呼ばれる。具体的には Helm Chart で以下のようなファイルを作成する。

.
├── Chart.yaml
├── templates
│   ├── argo-cd.yaml
│   └── namespace.yaml
└── values.yaml

Chart.yaml は適当な内容でよい。

apiVersion: v1
name: app-of-apps
version: 0.0.1

values.yaml には管理対象となる Application のデフォルト値を設定しておく。

metadata:
  namespace: argo-cd
spec:
  destination:
    server: https://kubernetes.default.svc
  source:
    repoURL: https://github.com/chroju/infrastructure
    targetRevision: HEAD

templates 内に app 1つにつき1ファイルを作成していく。ここで Application を管理していく。以下では、 chroju/infrastructure レポジトリの kubernetes/namespace 配下が Application の同期対象となる。

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: namespace
  namespace: {{ .Values.metadata.namespace }}
spec:
  project: default
  source:
    repoURL: {{ .Values.spec.source.repoURL }}
    path: kubernetes/namespace
    targetRevision: {{ .Values.spec.source.targetRevision }}
  destination:
    server: {{ .Values.spec.destination.server }}
    namespace: default
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

この Helm Chart を管理する Application をさらに作っていくとさすがに切りがないので、ここだけは argocd app create コマンドにより手動で Argo CD へ Application を作成する。すると画面上では以下のように、親 app から各 Application がぶら下がるような形になる。

Image from Gyazo

今後 Application を追加したい場合は、先の Helm の template にファイルを追加していくだけでいいので、今後は Git 上の操作だけで manifest を apply できる、 GitOps の環境ができあがる。

Argo CD UI へのアクセス

なお、k8s 上のアプリケーションを expose する手段をまだ持っておらず、 Argo CD は port forward でアクセスしている。常時アクセスしたいものではないし、これでも別に良いような気もしているが、気が向いたら何か手段を講じるかもしれない。

$ kubectl port-forward argo-cd-argocd-server-XXXXXXXXX-XXXXX 8080:8080

Next

とりあえず、 k8s cluster とその上で動く resource がすべて declarative に管理できる状態がこれで出来上がった。まだまだ課題はあるので、ゆっくり育てていきたい。

  • 先述の Argo CD port forward をどうするか
  • Argo CD ログインを何らかの OAuth へ変更したい
  • 監視を実施したい
  • Reserved Instance を購入したい
  • 定期的なアップデートを実施していきたい

実は1年近く前にも kubeadm + ConoHa でクラスター構築したのだが、当時の設定を何も情報残していないし、管理が頓挫したので今回が再挑戦になる。今回こそは続けていきたいところ。