前回のあらすじ
- 本番環境を構築した
- Dockerfileを作ってそこからDockerImageを作った
この記事ですること
- k8sマニフェストを作る
- 動かす
k8sマニフェスト作成
前回の記事は準備でここからが本題。
k8sを動かすにはmanifestという物を作って渡してあげる必要がある。
正確にはなくても長いコマンドでパラメータ渡せば行けるんだが、みんなDockerではDocker-compose -f
使うよね?ってことだ。
設定はyamlに残すべき。
さて書いていこう。
まずは分かりやすいMongoDBの設定から。
mongo-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mongo-sts
spec:
selector:
matchLabels:
app: mongo-pod
serviceName: mongo-svc
replicas: 3
template:
metadata:
labels:
app: mongo-pod
spec:
terminationGracePeriodSeconds: 10
containers:
- name: mongo-container
image: mongo:4.4
command:
- mongod
- "--replSet"
- rs0
- "--bind_ip"
- 0.0.0.0
ports:
- containerPort: 27017
volumeMounts:
- name: mongo-pvc
mountPath: /data/db
volumeClaimTemplates:
- metadata:
name: mongo-pvc
spec:
accessModes:
- "ReadWriteOnce"
resources:
requests:
storage: 10Gi
…???
やっていることを説明していく。
まずは先頭のkind:statefulsetって何だろうか。
これはステートフルなアプリケーションを動かす際に指定する。
…全く解説になってないのでとりあえずDBにはこれ使う。
理由としてはアプリケーションの接続するDBをコンテナ名で指定したいのと、DB1つ1つに永続ボリュームを割り当てたい為だ。
https://kubernetes.io/ja/docs/concepts/workloads/controllers/statefulset/
安定した一意のネットワーク識別子
安定した永続ストレージ
ってところが欲しい感じ。
逆にこの辺が要らないStrapiサーバーは違うの使ってるわけだがそれは後述。
ネットワーク識別子って所だが、k8s内なら大抵Pod名で名前解決できるのでPod名となる。
Podってのは1つ以上のコンテナの集まり。今回はPod1つにコンテナ1つなのでコンテナと同じと見てもそこまで支障はない。
で、これを起動した時のPod名になるのがmetadata:nameだ。
今回はmongo-stsなので、mongo-sts-0とかで立ち上がる予定。
次にspec。
ここから設定項目になる。
selectorというのが監視するPodがどれかというのを設定する場所。
今回は app: mongo-pod
というラベルが付いたPodを監視する。
監視するにしても何を基準に見守るのか?
そこで replicas: 3
である。
要はPod3つ作って維持してねという指示を出しているわけだ。
これでこのマニフェストを実行したらmongo-podってのが3つ出来ることは分かった。
じゃあPodの中身ってどんなんよ?ということがtemplete:
以下にかかれている。
まずはlabelが app: mongo-pod
。監視対象である。
こちらもspec以下が設定項目。
名前はmongo-containerでDockerImageにmongo:4.4を使っている。
そしてmongodコマンドで起動するように設定を書いている。
portsの内容含め、Dockerに近いのでまだ読めるほうではないだろうか。
その次に volumeMounts
というのがあるが、これは名前の通りストレージをマウントしている。
コンテナの中の/data/db
にmongo-pvc
っていうところから分捕ってきたストレージをマウントしてね。っていう指示。mongo-pvc
は何っていうのは下のvolumeClaimTemplates
に書いてある。
英語まんまでボリュームを請求するテンプレートである。
ここでは10Giちょうだいといっている。
誰が出すのってなるがそのあたりはMinikubeやDocker for mac/windowsがよしなにやってくれるので気にしなくていい。
気になる人はPersistentVolumeとDynamic provisioningあたりで調べればいいと思う。
https://kubernetes.io/ja/docs/concepts/storage/dynamic-provisioning/
https://minikube.sigs.k8s.io/docs/handbook/persistent_volumes/
設定説明ここまで。
どうせ一発では理解できないし、とりあえずローカルで動かしてみよう。
Docker for mac/windows環境なら設定一つ変えるだけでkubectlコマンドが使えるのでテスト最適。
kubectl apply -f mongo-statefulset.yml
created的な文字が出てくるはずだ。
kubectl get pods
NAME READY STATUS RESTARTS AGE
mongo-sts-0 1/1 Running 0 11d
mongo-sts-1 1/1 Running 0 11d
mongo-sts-2 1/1 Running 0 11d
mongo-sts-0などがrunningになっていれば正常起動している。
AGEは起動時間なんで1mとか短い値になってるはず。
一応Dockerよろしくコンテナの中に入ることも出来る。
sudo kubectl exec -it mongo-sts-0 -- /bin/bash
これで中に入れるんで、mongoコマンドでも打ってちゃんと動いているか確認しておこう。
次にStrapiの立ち上げ。
strapi-deployment.yaml
今度はdeploymentである。何これ。
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: strapi-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: strapi-deployment
labels:
app: strapi-deployment
spec:
replicas: 3
selector:
matchLabels:
app: strapi-pod
template:
metadata:
labels:
app: strapi-pod
spec:
containers:
- name: strapi-container
image: tim0401/dreamer-strapi:latest
ports:
- containerPort: 1337
env:
- name: PORT
value: "1337"
- name: ADMIN_JWT_SECRET
valueFrom:
secretKeyRef:
name: secret
key: admin-jwt-secret
- name: DATABASE_HOST
value: "mongo-sts-0.mongo-svc.default.svc.cluster.local:27017,mongo-sts-1.mongo-svc.default.svc.cluster.local:27017,mongo-sts-2.mongo-svc.default.svc.cluster.local:27017/?replicaSet=rs0"
- name: DATABASE_PORT
value: "27017"
- name: DATABASE_NAME
value: "dreamer-strapi"
volumeMounts:
- name: strapi-data
mountPath: "/dreamer-strapi/app/public/uploads"
volumes:
- name: strapi-data
persistentVolumeClaim:
claimName: strapi-pvc
PersistentVolumeClaim
…ボリュームくれくれ君。
今回も10Gi要求。Deployment
が何なのかというとReplicaSet
を管理するものである。ReplicaSet
が何なのかというとPod
を管理するものである。StatefulSet
との違いは順番に作られなかったり、コンテナ名が指定できないので特定のコンテナにネットワークアクセス出来なかったり、ボリューム共有だったりする。
要はステートがないものに使えってことらしい。
全部StatefulSet
じゃ駄目なのとか思うけど管理が楽とかなんか理由があるんでしょうね。
あとReplicaSet
って意識して使うことあるんかな…?
さて説明だが、途中まではmongoと被るのでカット。
要はPod3つ作って。以上。
その後もdocker-composeで見たこれって内容。
まあ自分で作ったイメージだしそりゃ同じ内容のenvいるわな。
ADMIN_JWT_SECRETがsecretってなってるが、secret.yamlを後で紹介するのでそっちの値を参照していると思ってもらえればいい。
パスワードとかはそっちに書いて読み込ませる方式。
DATABASE_HOSTがすごいことになってるが、mongoのreplicasetはこんな感じでアクセスできるらしい…3つのPodのアドレスを連ねて書いている。
一応動くんだけど、これ本当に正しいのか…。
残りはボリュームマウントしてるだけ。
書き方の決まりはあるけどやってることはそこまで難解ではない。
mongo-service.yaml
apiVersion: v1
kind: Service
metadata:
name: mongo-svc
labels:
name: mongo-svc
spec:
type: ClusterIP
ports:
- port: 27017
targetPort: 27017
clusterIP: None
selector:
app: mongo-pod
お次はサービス。
サービスっていうのはPodを束ねて内部や外部からアクセス出来るポイントを作るもの。
今回の場合、mongo-svc
っていうサービスを通してmongo-pod
のアドレス解決が出来るようになって内部からアクセスできるようになる。
上の設定でmongo-sts-0.mongo-svc.default.svc.cluster.local:27017
ってのがあったけどmongo-svc
の文字が見えると思う。
これがあるからアクセス出来るわけだ。
やってることはそれだけだけど重要な役目。
ポートはmongo-pod
に合わせて27017。
strapi-service.yaml
apiVersion: v1
kind: Service
metadata:
name: strapi-svc
spec:
selector:
app: strapi-pod
ports:
- port: 1337
targetPort: 1337
nodePort: 30000
type: NodePort
今度はサービスでもNodePort
って種類のもの。
ちなみに上のはClusterIP
。多分クラスタ内だけのIPって意味。NodePort
は外部にPodを公開できる。ports:nodePort
が30000に設定されているのでlocalhost:30000で公開される。
ポートは指定しなければ30000~32767
がランダムで割り当てられるけどそれじゃ使えないので固定。
https://kubernetes.io/ja/docs/concepts/services-networking/service/
一応上記の範囲で指定したほうがいいと思う。
他も出来るかもしれないけどやったことない。
これでstrapi-pod
にlocalhost:30000でアクセスできるようになる。
secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: secret
type: Opaque
stringData:
admin-jwt-secret: "<your-secret>"
シンプル。strapi-deployment
で使ったadmin-jwt-secret
はここで指定している。
シークレットは生成していれといてください。
立ち上げ
ここまでお疲れ様でした。
書いてて疲れるので数ヶ月経った私が読んでも相当疲れることだろう。
全ての準備が整った(はず)なので、立ち上げてみよう。
環境はUbuntuの本番でするのでもいいけど、ローカルの環境でとりあえず試した方が上手く動かなかった時に修正しやすいと思う。
立ち上げるのはコマンド一発でサクッと終わる。
kubectl apply -f ./
カレントのマニフェスト全適用である。
ちなみに、これだけだとStrapiがコケる。
MongoDBの中身に対してレプリケーション設定をしないといけない。
これをマニフェストに書かないのは初回のみすることだから、マニフェスト変更とかでPodの再生成がかかった際にやってほしくないため。
立ち上げ後のMongoDBレプリケーション設定
kubectl exec -it mongo-sts-0 -- /bin/bash
mongo mongo-sts-0.mongo-svc
config = {
_id : "rs0",
members: [
{ _id: 0, host: "mongo-sts-0.mongo-svc:27017" },
{ _id: 1, host: "mongo-sts-1.mongo-svc:27017" },
{ _id: 2, host: "mongo-sts-2.mongo-svc:27017" },
]
}
rs.initiate(config)
rs.status()
コンテナに入ってmongoのreplicasetを3台で構成する設定。
これで3台によるレプリケーションをしてくれる。rs.status()
でreplicasetの状態を長々と出してくれたら成功。
確認
$ sudo kubectl get all
NAME READY STATUS RESTARTS AGE
pod/mongo-sts-0 1/1 Running 0 11d
pod/mongo-sts-1 1/1 Running 0 11d
pod/mongo-sts-2 1/1 Running 0 11d
pod/strapi-deployment-754494fd88-74bd5 2/2 Running 0 4d19h
pod/strapi-deployment-754494fd88-dcft2 2/2 Running 0 4d19h
pod/strapi-deployment-754494fd88-smf2f 2/2 Running 0 4d19h
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 13d
service/mongo-svc ClusterIP None <none> 27017/TCP 13d
service/strapi-svc NodePort 10.102.209.245 <none> 1337:30000/TCP 12d
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/strapi-deployment 3/3 3 3 11d
NAME DESIRED CURRENT READY AGE
replicaset.apps/strapi-deployment-547449485f 0 0 0 8d
replicaset.apps/strapi-deployment-6bd7bcd9d7 0 0 0 11d
replicaset.apps/strapi-deployment-6dc6597556 0 0 0 8d
replicaset.apps/strapi-deployment-6df77bdbf6 0 0 0 9d
replicaset.apps/strapi-deployment-754494fd88 3 3 3 4d19h
NAME READY AGE
statefulset.apps/mongo-sts 3/3 11d
綺麗に立ち上がるとこんな形でちょっと達成感がある。
苦戦したところが多すぎて苦労に見合ってるかは微妙かもしれない。
長くなったがこれでLAN内からStrapiにアクセス出来るようになったはずだ。
LAN内の他のPCから構築したPCのIPアドレス:30000
にアクセスしてみよう。
Strapiの見慣れた画面が出てくるはずだ。
localhostからは行けるのにLAN内の他PCからは見れない場合、Firewallが邪魔をしている可能性があるので一時的にポート開放をしておくといい。
次は外部からアクセスするためにNginxによるリバースプロキシを作っていく。
とはいえ、やらなくてもアクセス出来たりするし今回の比じゃないくらいさくっと終わるので書くのが楽そうだ。
今回貼ったマニフェストはGithubに置いてるので最新の物が見たかったらどうぞ。
https://github.com/Tim0401/dreamer-strapi/tree/master/manifest