前回はMySQLがk8s上で動いたわーい、というところまでやった。今回はRubyOnRailsを動かしてみる。
前提として動かすRailsアプリが必要なんだけど、/docker-mysql-railsというdocker-composeで動かせるものがあったのでありがたくforkして利用することにした(takaishi/docker-mysql-rails)
MySQLの起動(前回と同じ)
前回と同じでOK。
apiVersion: v1 kind: ReplicationController metadata: name: mysql spec: replicas: 1 selector: app: mysql template: metadata: name: mysql labels: app: mysql spec: containers: - name: mysql image: mysql env: - name: MYSQL_ROOT_PASSWORD value: passw0rd ports: - containerPort: 3306 --- apiVersion: v1 kind: Service metadata: name: mysql spec: ports: - port: 3306 targetPort: 3306 protocol: TCP type: LoadBalancer selector: app: mysql
作成。
$ kubectl create -f ./mysql.yml
Railsの起動
まずはイメージを用意する
kubernetesはイメージのビルドはできないようなので、dockerコマンドなどでイメージを作成して、レジストリに置く必要がある。DockerHubを使う手もあるが、仕事の場合、そうはいかない可能性も考えられる。今回はローカルにプライベートレジストリを構築し、そこにプッシュしてみる。
さて、プライベートなDockerレジストリを構築するにはどうしたらいいかなと思っていたら、 Local development with Kubernetes という記事を発見した。k8s上にレジストリを構築するもので、手っ取り早そうなのでこれを使うことにする。
apiVersion: v1 kind: ReplicationController metadata: name: kube-registry-v0 namespace: kube-system labels: k8s-app: kube-registry version: v0 spec: replicas: 1 selector: k8s-app: kube-registry version: v0 template: metadata: labels: k8s-app: kube-registry version: v0 spec: containers: - name: registry image: registry:2 resources: limits: cpu: 100m memory: 100Mi env: - name: REGISTRY_HTTP_ADDR value: :5000 - name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY value: /var/lib/registry volumeMounts: - name: image-store mountPath: /var/lib/registry ports: - containerPort: 5000 name: registry protocol: TCP volumes: - name: image-store emptyDir: {} --- apiVersion: v1 kind: Service metadata: name: kube-registry namespace: kube-system labels: k8s-app: kube-registry kubernetes.io/name: "KubeRegistry" spec: selector: k8s-app: kube-registry ports: - name: registry port: 5000 protocol: TCP --- apiVersion: v1 kind: Pod metadata: name: kube-registry-proxy namespace: kube-system spec: containers: - name: kube-registry-proxy image: gcr.io/google_containers/kube-registry-proxy:0.3 resources: limits: cpu: 100m memory: 50Mi env: - name: REGISTRY_HOST value: kube-registry.kube-system.svc.cluster.local - name: REGISTRY_PORT value: "5000" - name: FORWARD_PORT value: "5000" ports: - name: registry containerPort: 5000 hostPort: 5000
kubectl apply -f local-registry.yml
これで、ローカリリポジトリの準備が整った。後は、動かしたいRailsアプリのイメージを作成し、レジストリにプッシュすれはOK。
$ docker build -t localhost:5000/r_takaishi/docker-mysql-rails . $ docker push localhost:5000/r_takaishi/docker-mysql-rails
いよいよ起動だ
Rails用のマニフェストは以下の通り。環境変数でDBのホストやパスワード等を渡している。また、コンテナの起動前にdb:createやdb:migrateを行うようにしてみた(が、このPostStartの実行ログがどこに保存されるのかがいまいち分かっていない)。
apiVersion: v1 kind: ReplicationController metadata: name: rails spec: replicas: 1 selector: app: rails template: metadata: name: rails labels: app: rails spec: containers: - name: rails image: localhost:5000/r_takaishi/docker-mysql-rails command: ["bundle", "exec", "rails", "s", "-p", "3000", "-b", "0.0.0.0"] env: - name: RAILS_ENV value: development - name: MYSQL_HOST value: mysql.default.svc.cluster.local - name: MYSQL_USER value: root - name: MYSQL_PASSWORD value: passw0rd lifecycle: postStart: exec: command: - /myapp/post-start.sh ports: - containerPort: 3000 --- apiVersion: v1 kind: Service metadata: name: rails spec: ports: - port: 3000 targetPort: 3000 protocol: TCP type: LoadBalancer selector: app: rails
$ cat post-start.sh #!/bin/bash RAILS_ENV=$RAILS_ENV bundle exec rake db:create RAILS_ENV=$RAILS_ENV bundle exec rake db:migrate
applyする。
kubectl apply -f ./rails.yml
こんな感じで、mysqlとrailsのpodが起動した状態となる。
$ kubectl get pods NAME READY STATUS RESTARTS AGE mysql-8kd4q 1/1 Running 2 4d rails-l15mm 1/1 Running 0 28m
minikubeでアクセス先URLを取得して、アクセスする。
$ minikube service rails --url http://192.168.99.100:31452
やったー!
スケールしてみる
コンテナの台数を増やしてみる。railsのpodが1台の所から始めよう。
$ kubectl get pod NAME READY STATUS RESTARTS AGE mysql-8kd4q 1/1 Running 2 4d rails-8cnzn 1/1 Running 0 6m
scaleコマンドがある。便利だ。5台にしてみよう。
$ kubectl scale rc rails --replicas=5 replicationcontroller "rails" scaled
そうすると、podが5個に増える。
$ kubectl get pods NAME READY STATUS RESTARTS AGE mysql-8kd4q 1/1 Running 2 4d rails-8cnzn 1/1 Running 0 7m rails-nwz9l 0/1 ContainerCreating 0 2s rails-q4f5z 0/1 ContainerCreating 0 2s rails-tfcjw 0/1 ContainerCreating 0 2s rails-zbjqw 0/1 ContainerCreating 0 2s
起動完了。30秒弱で1台から5台にスケールアウトできた。
$ kubectl get pods NAME READY STATUS RESTARTS AGE mysql-8kd4q 1/1 Running 2 4d rails-8cnzn 1/1 Running 0 7m rails-nwz9l 1/1 Running 0 25s rails-q4f5z 1/1 Running 0 25s rails-tfcjw 1/1 Running 0 25s rails-zbjqw 1/1 Running 0 25s
減らすのも簡単。scaleコマンドで台数を1にしてやれば、1台になるまでコンテナが減ってくれる。
まとめ
RailsアプリとMySQLをKubernetes上で動かし、アプリの台数を増やしたり減らしたりしてみた。台数の増減がとにかく楽なので、仕事でも使いたいなあと思います。
拝見いたしました。参考になりました。
一つ質問なのですが、LoadBalancerで双方のserviceを作った時にmysqlは外部に公開されてしまうのではないでしょうか?
確かに、LoadBalancerでサービスを作った場合はMySQLが外部に公開されてしまう可能性がありますね。1つ前のブログ記事で試していた、MySQLを動かすマニフェストをそのまま使ったのでこうなっていますが、実際にはRails用のPodからしかアクセスできないようにするのがよいのではないかと思います。