Help us understand the problem. What is going on with this article?

Docker ComposeからMinikube + Komposeに移行してみよう

はじめに

Kubernetesがコンテナオーケストレーションツールのデファクトになったといわれて久しい1ですが、今年のAWS re:InventではAmazon EKS2の発表もあり、これからKubernetesに取り組もうという人もいるのではないかと思います。

かくいう私もその一人で、最近この辺りの技術に入門して色々と試していたので、今日はそのまとめを記します。

更新履歴

  • 2020-05-09 Compose on Kubernetesについて追記
  • 2017-12-12 初稿投稿

用語解説

Minikube

Kubernetesクラスタをローカルマシン上で構築できるようにしてくれるものです。

Kubernetesクラスタを自前で一から構築するのは非常に大変そう(やったことはありません)なのですが、これを使うと簡単に試すことができます。

CIなどでも活用できそうです。

Kompose

Docker Composeの設定ファイルをKubernetes向けに変換するツールです。

また、変換によって生成されたリソース群を、docker-composeライクなインタフェースで制御することもできます。

この記事で行うこと

  1. PostgreSQLをバックエンドとするシンプルなRailsのWebアプリケーションを用意します。
  2. このWebアプリケーションをDocker化して、Docker Composeを使った開発環境を構築します。
  3. Komposeを使ってDocker Composeの設定をKubernetes向けに変換し、Minikube上で動かします。

以降では、DockerやDocker Composeについては、ある程度知っているという前提で書きます。

使用するソースコードや設定ファイルは https://github.com/progrhyme/compose-to-minikube にまとめましたので、適宜ご参照ください。

2020-05-09追記: Compose on Kubernetesについて

2018年12月、Docker社がCompose on Kubernetesというツールを発表しました3

これを使うと、設定をKubernetes向けに変換することなく、次のようなコマンドで直接Kubernetesクラスタにデプロイすることが可能です。

docker stack deploy --namespace my-app --compose-file /path/to/docker-compose.yml mystack

ただし、利用にはDocker DesktopまたはDocker Enterpriseが必要とのことです。
利用できるのであれば、こちらの方が便利なケースもありそうです。

必要なもの

ツール 筆者環境のバージョン 公式インストールガイド
Docker 17.05.0-ce https://docs.docker.com/engine/installation/
Docker Compose 1.17.0 https://docs.docker.com/compose/install/
kubectl v1.8 https://kubernetes.io/docs/tasks/tools/install-kubectl/
Minikube v0.24.1 https://github.com/kubernetes/minikube#installation
Kompose 1.5.0 http://kompose.io/installation/

全てのツールがWindows, Mac OS, Linuxの各プラットフォームに対応しているので、いずれかの環境であれば動かせると思います。

※ここでは、個々の細かいインストール手順は省略します。

筆者はUbuntu 16.04で作業しました。

Railsアプリケーションの作成

PostgreSQLを使うアプリケーションを次のように作成します。

rails new my_app --database=postgresql

後の作業でDB接続先を環境変数から渡すようにするので、 config/database.yml を次のように編集しておきます。

config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  url: <%= ENV['DATABASE_URL'] %>

development:
  <<: *default

test:
  <<: *default

production:
  <<: *default

動作確認をするため、適当なModelをControllerと共に生成しておきます。

bundle exec rails g scaffold person name:string age:integer

これで、 /people/people/new などのエンドポイントによって、DBのCRUDが試せるようになりました。

アプリケーションをDocker化する

上のRailsアプリケーションをDockerで動かすため、下のようなDockerfileを書きました。

Dockerfile
FROM ruby:2.4.2

RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs

RUN mkdir /app
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . ./

CMD bundle exec rails server -b 0.0.0.0 -p ${PORT:-3000}

下のコマンドで、Dockerイメージのビルドを試すことができます。

docker build -t progrhyme/compose2minikube:v1 .

Docker Composeによる開発環境構築

上で用意したRailsアプリケーションをDBと連携して動作させるため、Docker Composeによってローカルマシン上でクラスタを構築します。

下のような設定ファイルを docker-compose.yml として作成しました。

docker-compose.yml
version: "3"

services:
  db:
    image: postgres:9.5
    environment:
      - POSTGRES_USER=${MY_APP_DATABASE_USER}
      - POSTGRES_PASSWORD=${MY_APP_DATABASE_PASSWORD}
      - POSTGRES_DB=${MY_APP_DATABASE_NAME}
  rails:
    build:
      context: .
    ports:
      - "3000:${PORT:-3000}"
    environment:
      - DATABASE_URL=postgres://${MY_APP_DATABASE_USER}:${MY_APP_DATABASE_PASSWORD}@db:5432/${MY_APP_DATABASE_NAME}
    depends_on:
      - db

DockerHubで提供されているPostgreSQLのイメージでは、上のような環境変数によって初期データベースユーザ名、パスワード、データベース名を設定することができます。

${MY_APP_DATABASE_USER}, ... といった変数は下のように環境変数で設定しました。

export MY_APP_DATABASE_USER=myapp
export MY_APP_DATABASE_PASSWORD=password
export MY_APP_DATABASE_NAME=my_app_development

docker-compose.ymlでは、上の設定のように環境変数を直接YAMLに記述して、比較的シンプルな設定ファイルを作ることができます。

また、上の設定中の DATABASE_URL で記しているように、 rails のコンテナ内からはservice db に対してホスト名 db でアクセスすることができます。

動作確認

上で構築したクラスタを動かしてみます。
下のコマンドでdbとrailsのコンテナを起動できます。

docker-compose up

http://0.0.0.0:3000 でRailsサーバが稼働しますが、DBマイグレーションを実施していないため、アクセスするとエラーになってしまいます。
マイグレーションは以下のように実行できます:

docker-compose exec rails rake db:migrate

ここで rails はdocker-composeから見たserviceの識別名です。

再度アクセスすると、Railsの画面を確認できるでしょう。

http://0.0.0.0:3000/people にアクセスすると、scaffoldで生成したRails開発者にお馴染みのコントローラ画面が表示されます。

image.png

KomposeによってMinikube上でアプリケーションを動かす

以下では、先の手順で作成したDocker ComposeのクラスタをMinikube上で動かしていきます。

下準備

Minikubeを立ち上げておく

まず、予めMinikubeを起動しておきましょう。
※必要なツール類のインストールは済んでいるものとします。

minikube start

初回はコンテナイメージのpullなどでかなり時間が掛かると思います。
無事に起動したら、下のようなコマンドで状態を確認することができます。

minikube status
minikube dashboard # ブラウザでダッシュボードを開く

minikube startによって、kubectlのコンテキストにMinikubeがセットされ、kubectlコマンドでクラスタに対する操作が可能になります。

ローカルでDockerレジストリを動かす

Kubernetesにはコンテナイメージをビルドする機能はありません。
従って、サンプルアプリケーションのカスタムイメージをどこかのレジストリにpushし、そこからpullするように設定する必要があります。

サンプルなのでDockerHubに置いても良いのですが、ここでは公式のDocker Registryイメージを利用して、ローカルでレジストリサーバを動かすことにしました。

以下のように、Dockerで簡単にレジストリサーバを動かすことができます:

docker run -d -p 5000:5000 \
  -v ~/.dockerregistry:/var/lib/registry \
  --restart always \
  --name registry \
  registry:2

ここでは、 ローカルマシンの ~/.dockerregistry ディレクトリを永続化用のボリュームとしてマウントしています。

このレジストリに、上でビルドしたDockerイメージをpushしておきます。

docker tag progrhyme/compose2minikube:v1 localhost:5000/progrhyme/compose2minikube:v1
docker push localhost:5000/progrhyme/compose2minikube:v1

Docker Compose設定を変換する

上の手順で作った docker-compose.ymlkompose convert で変換してみます。

$ cd <docker-compose.ymlがあるディレクトリ>
$ kompose convert
INFO Kubernetes file "db-service.yaml" created    
INFO Kubernetes file "rails-service.yaml" created 
INFO Kubernetes file "db-deployment.yaml" created 
INFO Kubernetes file "rails-deployment.yaml" created 

上手く設定を変換することができました。

ただし、 kompose up してローカルマシンからサービスにアクセス可能にするために、2点ほど修正する必要がありました。

  1. docker-compose.yml で、コンテナイメージとしてローカルレジストリにpushしたイメージを指定するようにしておく
  2. rails-service.yaml で、Serviceのtypeを変更

それぞれの差分としては以下のようになります:

# docker-compose.yml
       :
       - POSTGRES_DB=${MY_APP_DATABASE_NAME}
    rails:
-     build:
-       context: .
+     image: localhost:5000/progrhyme/compose2minikube:v1
      ports:
        - "3000:${PORT:-3000}"
      environment:
       :

# rails-service.yaml
     :
     targetPort: 3000
    selector:
      io.kompose.service: rails
+   type: NodePort
  status:
    loadBalancer: {}

2について、KubernetesのServiceのtypeはデフォルトではClusterIPとなっており、クラスタ内からしかアクセスできません。
クラスタ外からアクセス可能にするには、NodePortLoadBalancerにする必要があります。

動作確認

kompose convertで生成した設定ファイル内のリソースには io.kompose.service といったキーのlabelやselectorが付加されています。
Komposeはこれらのlabel等を使ってリソースを管理しているのでしょう。

kompose upすると、リソース群をKubernetesクラスタ上に作成します。

$ kompose up
INFO We are going to create Kubernetes Deployments, Services and PersistentVolumeClaims for your Dockerized application. If you need differe
nt kind of resources, use the 'kompose convert' and 'kubectl create -f' commands instead. 

INFO Deploying application in "default" namespace 
INFO Successfully created Service: db             
INFO Successfully created Service: rails          
INFO Successfully created Deployment: db          
INFO Successfully created Deployment: rails       

Your application has been deployed to Kubernetes. You can run 'kubectl get deployment,svc,pods,pvc' for details.

rails, dbのDeploymentとServiceが作成されました。

kubectlコマンドでPodの状態を確認してみましょう。

$ kubectl get pods
NAME                     READY     STATUS        RESTARTS   AGE
db-65644f9968-4zx5w      1/1       Running       0          5s
rails-6896549fc6-45mmw   1/1       Running       0          5s

新しく作ったdbコンテナは空っぽなので、またDBマイグレーションが必要です。
kubectlコマンドを使ってrailsコンテナでコマンドを実行します。

kubectl exec -it rails-6896549fc6-45mmw rake db:migrate

さて、実は先ほど編集した rails-service.yaml の変更はクラスタに反映されていません。
反映するためには、 kubectl apply コマンドを実行します。

$ kubectl apply -f rails-service.yaml
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
service "rails" configured

警告は出ますが、変更は適用されました。

kubectlコマンドとminikubeコマンドで確認してみます。

$ kubectl get services
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
db           ClusterIP   None            <none>        55555/TCP        6m
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP          1d
rails        NodePort    10.96.140.120   <none>        3000:31308/TCP   6m

$ minikube service list
|-------------|----------------------|------------------------|
|  NAMESPACE  |         NAME         |          URL           |
|-------------|----------------------|------------------------|
| default     | db                   | No node port           |
| default     | kubernetes           | No node port           |
| default     | rails                | http://127.0.0.1:31308 |
| kube-system | kube-dns             | No node port           |
| kube-system | kubernetes-dashboard | http://127.0.0.1:30000 |
|-------------|----------------------|------------------------|

ブラウザで http://127.0.0.1:31308 にアクセスすると、Railsが動いているのを確認できます。
または、 minikube service rails コマンドによって、該当のURLをブラウザで開くことができます。

所感

Kubernetesの設定はDocker Composeより複雑で、必要な事前知識も多いのですが、Komposeによってそれらをスキップして動作する設定を作れるのは便利だと思います。

MinikubeやKomposeによって、Kubernetesの開発環境もだいぶ便利になってきていると感じました。

本番でKubernetesを使うなら、開発環境はこんな感じで構築すると良さそうです。

今後やりたいこと

上で紹介した docker-compose.yml について、開発時はプロジェクトのディレクトリをマウントしておくと便利だと思いますが、Kubernetesでのやり方をまだ調べきれていないので、その辺りも試しておきたいなと思っています。

むすびに

思いのほか色々な要素を詰め込んだエントリになってしまったので、説明が足りなかったり、わかりにくくなっている部分があるかもしれません。
また、試したばかりのことも多いです。

何か誤りなどありましたら、コメントなどでお知らせ下さい。

参考

脚注

progrhyme
Software Engineer. Was @key-amb
https://progrhy.me/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした