repl.info

Rails + MySQL on Kubernetesを試す

前回はMySQLがk8s上で動いたわーい、というところまでやった。今回はRubyOnRailsを動かしてみる。

前提として動かすRailsアプリが必要なんだけど、suburi/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上で動かし、アプリの台数を増やしたり減らしたりしてみた。台数の増減がとにかく楽なので、仕事でも使いたいなあと思います。