勉強とか実験とかのためにネコ画像集めてるサイトを運用してる。
元々普通のVM上でdocker-composeで運用してたが、これをGoogle Kubernetes Engine (GKE)に引っ越ししてみた。
やるまでは「docker-composeでいいじゃん」とか思ってたけど、k8sは色々とサービス運用で必要な機能が揃っていて、プロとしてコンテナ運用するならこれをマスターしないとならないと思うようになった。
docker-composeは「開発環境でコンテナを動作させるためには便利」というような認識になった。
GKEを使用
kubernetesの勉強のためにクラスター構築をすること自体の難易度が高かった為マネージドサービスを使った。
(アドバイスもあったし、少しやってみて確かに難しかった)
GKEなら1年間3万円までの無料枠があったので採用した。
コンテナ構成
アプリケーションサーバーコンテナ
Railsで組んだアプリケーションが載っているコンテナ。
また、猫画像収集バッチ処理がrakeタスクで実装されていてcronで定期実行されている。
本当はこのバッチ処理は別コンテナに分離すべきだったがまだ出来てない。
このコンテナを複数つくると、各コンテナでバッチ処理が同時に動いてしまうので水平スケールができない。。
DBコンテナ
postgresqlが実行されているコンテナ。
データファイルがvolumeで永続化されている。
レプリケーションとかバックアップとかの設定は全くしてない。
本当はマネージドRDSを使うのが正解なんだと思う。
リバースプロキシコンテナ
ssl対応用のnginxが動いているリバースプロキシコンテナ。
k8sとかGKEになんかssl用の機能があって、もしかしたら不要だったりするのかも、、とか思ってる。
設定ファイル類
アプリケーションサーバーコンテナ
deployment.yaml
注意:
多分dbパスワードとか、RAILS_MASTER_KEYとかは環境変数で渡すのではなく、Secretを使って渡すべきだと思う。
今回はとにかく「動かすこと」を目的にしたので端折った。
apiVersion: apps/v1 kind: Deployment metadata: name: nekoneko-app-deployment spec: replicas: 1 # バッチ処理が入ってるから、レプリカ数を増やせない。。 selector: matchLabels: app: nekoneko-rails-pod template: # pod定義をここでやってる metadata: labels: app: nekoneko-rails-pod spec: containers: - name: nekoneko-rails image: asia.gcr.io/{your-project-name}/nekoneko_app:v0.0.4 # googleのコンテナレジストリに上がってるimageを指定 env: # 環境変数類 - name: DB_HOST value: nekoneko-db-service.default.svc.cluster.local # k8sが内部DNSで名前解決する。独自の命名ルールがある。 - name: DB_PORT value: "5432" - name: DB_USER_NAME value: db_user_name - name: DB_PASSWORD value: ********** - name: DB_DEVELOPMENT_DB_NAME # この辺はproduction用だけ渡しておけばよかったかも。 value: nekoneko_dev - name: DB_TEST_DB_NAME value: nekoneko_test - name: DB_PRODUCTION_DB_NAME value: nekoneko - name: SITE_NAME # これはこのrailsアプリケーションの事情で渡してるやつ value: nekoneko - name: RAILS_MASTER_KEY # railsのproduction環境で必要なやつ value: xxxxxxxxxxxxxxxxxxxxxxxxxxxxx - name: RAILS_LOG_TO_STDOUT # railsログを標準出力に吐くようにする。(コンテナ内にファイルで吐かれてもコンテナと共に消え去るので) value: "1" ports: - containerPort: 80
service.yaml
apiVersion: v1 kind: Service metadata: name: nekoneko-service spec: type: ClusterIP ports: - port: 80 targetPort: 80 protocol: TCP selector: app: nekoneko-rails-pod
DBコンテナ
statefulset.yaml
注意:
多分dbパスワードとかは環境変数で渡すのではなく、Secretを使って渡すべきだと思う。
今回はとにかく「動かすこと」を目的にしたので端折った。
これはdeploymentではなくstatefulsetを使ってる。
dbなど状態を持つようなコンテナはstatefulsetを使うらしい。
以前これをdeploymentで作ってた時、変更をデプロイしようとしたら失敗した。
原因はvolumeのマウント部分で、旧コンテナとのマウントが外れる前に新コンテナにマウントしようとして「同時にマウントはできない」とエラーが出た。
statefulsetにすることで、旧コンテナからのマウントを外してから新コンテナにマウントされるようになった。
ただし、ダウンタイムは発生するようになった。
apiVersion: apps/v1 kind: StatefulSet metadata: name: nekoneko-db-statefulset spec: replicas: 1 selector: matchLabels: app: nekoneko-db-pod serviceName: nekoneko-db-service template: metadata: labels: app: nekoneko-db-pod spec: volumes: - name: db-volume persistentVolumeClaim: claimName: nekoneko-disk containers: - name: db image: postgres:12 volumeMounts: - mountPath: /var/lib/postgresql/data name: db-volume env: - name: POSTGRES_USER value: db_user_name - name: POSTGRES_DB value: postgres - name: POSTGRES_PASSWORD value: **************** - name: PGDATA value: /var/lib/postgresql/data/db_files
service.yaml
apiVersion: v1 kind: Service metadata: name: nekoneko-db-service spec: selector: app: nekoneko-db-pod ports: - protocol: TCP port: 5432 targetPort: 5432
volume.yaml
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nekoneko-disk spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi
リバースプロキシコンテナ
statefulset.yaml
注意:
多分証明書ファイルはvolumeで扱うのではなく、Secretを使って渡すべきだと思う。
今回はとにかく「動かすこと」を目的にしたので端折った。
apiVersion: apps/v1 kind: StatefulSet metadata: name: reverce-proxy-statefulset spec: replicas: 1 selector: matchLabels: app: reverce-proxy-pod serviceName: reverce-proxy-service template: metadata: labels: app: reverce-proxy-pod spec: volumes: - name: reverce-proxy-volume persistentVolumeClaim: claimName: reverce-proxy-pvc containers: - name: reverce-proxy image: asia.gcr.io/{your-project-name}/reverse_proxy_server:v0.0.2 volumeMounts: - name: reverce-proxy-volume mountPath: /etc/letsencrypt ports: - containerPort: 80 - containerPort: 443
service.yaml
apiVersion: v1 kind: Service metadata: name: reverce-proxy-service spec: type: LoadBalancer # この設定でGKEがロードバランサーを用意してグローバルIPを振ってくれる ports: - port: 80 name: http targetPort: 80 protocol: TCP - port: 443 name: https targetPort: 443 protocol: TCP selector: app: reverce-proxy-pod
volume.yaml
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: reverce-proxy-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 100Mi
もうすぐ無料枠が終わりそう
1ヶ月運用で16000円くらいかかってた。無料枠が尽きると共にnekone.loveサービス終了かも。。