Railsアプリ開発のためのDocker/Kubernetes入門1 Docker編

RailsアプリケーションをKubernetes(k8s)で運用できるようにするための手順を書きます。

概要

この記事はシリーズ連載記事の第一回です。シリーズ全体の概要は次の通りです。

はじめに、DockerやKubernetesの概要について簡単に説明しつつ、 dockerコマンドやkubectlコマンドの基本的な使い方をチュートリアル風味で紹介します。

次に、ごく小さな仕様の具体的なRailsアプリを題材として、 Docker Composeの構成ファイルやKubernetesのマニフェストの具体的なサンプルと使い方を示し、 最終的にHelmを使ってKubernetesクラスタにデプロイする方法を説明します。

DockerとKubernetesの全機能を網羅的に学ぼうとすると膨大な時間が必要になるので、 この記事では「RailsアプリをKubernetesで運用すること」にフォーカスして一つ一つの概念や機能の詳細は必要最小限に絞り、 より詳細な資料へのポインタを置くに留めます。

シリーズ全体の構成は次の通りです。

  • 第一回 Docker編
    • 最小限のDocker入門
    • dockerコマンドのチュートリアル
  • 第二回 Docker Compose/Dockerfile編
    • 最小限のDocker Compose入門
    • Docker Composeを使った各種ミドルウェアのインストールと管理
    • RailsアプリケーションのDockerイメージの作り方
    • Docker Composeによるローカルプレビュー環境の構築
  • 第三回 Kubernetes入門編
    • 最小限のk8s入門
    • minikubeの使い方
    • kubectlコマンドのチュートリアル
  • 第四回 Kubernetes基礎編
    • kubectlコマンドとYAML形式のマニフェストファイルでRailsアプリをk8sにデプロイする方法
  • 第五回 Kubernetes応用編
    • 基礎編で残した課題の解決編
  • 第六回 Helm編
    • 最小限のHelm入門
    • HelmでRailsアプリをk8sにデプロイする方法

全てのサンプルコードはここにあります。

https://github.com/kwhrtsk/rails-k8s-demoapp

前提

  • 各種ツール類のインストール手順はmacOSでの作業を前提としています。
  • HomebrewHomebrew-Caskを使います。
    • Homebrew-Caskのインストールはbrew tap caskroom/cask
  • Docker for Macを使います。
  • k8s関連ツールのインストール手順は後述します。
  • ツールのインストール手順を除けば、Linuxでもおおよそ同じ手順で動作を確認できると思います。

それぞれ下記のバージョンで動作を確認しています。

名称 バージョン
macOS High Sierra(10.13.4)
Docker for Mac 18.0.3.1-ce-mac65
Ruby 2.5.1
Rails 5.2.0
minikube 0.27.0 (k8s 1.10.0)
kubectl 1.10.2
helm 2.9.1
hyperkit v0.20171204-60-g0e5b6b
virtualbox 5.2.8

最小限のDocker入門

Docker初心者がRailsアプリをk8sで動かすまでに最低限必要なDockerについての知識とdockerコマンドの操作方法を書きます。 Rails固有のトピックを知りたい人は Docker Compose/Dockerfile編 までスキップしてください。

Dockerとは

LXC(Linux Containers)と呼ばれる技術を使ってアプリケーションの開発やデプロイを行うためのツール及びプラットフォームです。 LXCやDockerについて解説されたドキュメントは山ほどあるのでここでは詳細は割愛します。

dockerのコマンド体系について

2017年1月にリリースされたDocker 1.13で docker コマンドの構成が整理されました。 アナウンスは Introducing Docker 1.13 - Docker BlogCLI restructuredの部分です。

「旧コマンドは引き続きサポートするが、新コマンドの使用を勧める」とのことなので このドキュメントでは新しいコマンド体系で説明します。 ただ、古いドキュメントには旧コマンド体系で書かれているものも多いため、 対応する旧コマンドについても紹介します。

このドキュメントで紹介するコマンドの新旧対応は下記の通りです。 基本的にはimageかcontainerのサブコマンドへの移動ですが、一部違うものがあるので太字にしています。

旧コマンド 新コマンド 説明
docker pull docker image pull イメージを取得する
docker images docker image ls イメージの一覧を表示する
docker rmi docker image rm イメージを削除する
docker run docker container run コンテナを起動する
docker ps docker container ls コンテナの一覧を表示する
docker exec docker container exec 起動中のコンテナで新しいコマンドを実行する
docker logs docker container logs コンテナのログを表示する
docker rm docker container rm コンテナを削除する

以降の節で順にこれらのコマンドの使い方を説明します。見出しの括弧は旧コマンドです。

また、各節の終わりにリファレンスへのリンクを置いていますが、 少なくとも本稿の執筆時点においては旧コマンドの方が詳細に書かれているので、必要に応じてそちらも参照してください。 なお日本語版のドキュメントにはまだ新コマンド版のリファレンスはありません。

シェルの補完について

dockerのサブコマンドは、 861162a44 のようなハッシュ値や、 romantic_neumann のようにランダムな英単語の組み合わせで自動生成されたコンテナ名をパラメータとして受け取ります。

Docker for Macにはbashやzshでコマンドの補完を行うためのスクリプトが同梱されていますが、 ただインストールするだけでは有効になりません。 補完のための設定については別に記事を書いたのでこちらを参照してください。

bash/zshとfzfでDocker関連コマンドの補完を行う方法

docker image pull (docker pull): イメージを取得する

イメージとはコンテナの雛形です。docker image pullコマンドでリポジトリとタグを指定し、イメージを取得します。 MySQLの公式リポジトリから5.7.21のタグが付いたイメージを取得する場合は下記のようにします。

$ docker image pull mysql:5.7.21
5.7.21: Pulling from library/mysql
2a72cbf407d6: Pull complete
38680a9b47a8: Pull complete
4c732aa0eb1b: Pull complete
c5317a34eddd: Pull complete
f92be680366c: Pull complete
e8ecd8bec5ab: Pull complete
2a650284a6a8: Pull complete
5b5108d08c6d: Pull complete
beaff1261757: Pull complete
c1a55c6375b5: Pull complete
8181cde51c65: Pull complete
Digest: sha256:691c55aabb3c4e3b89b953dd2f022f7ea845e5443954767d321d5f5fa394e28c
Status: Downloaded newer image for mysql:5.7.21

タグは、多くの場合バージョンを指します。ただし、ここでいうバージョンはイメージのバージョンではなく、 アプリケーションのバージョンであることが多いため、 同じタグを指定してもタイミングによって違うイメージを取得するケースがある点に注意が必要です。

例えばmysql:5.7は現時点ではmysql:5.7.21と同じイメージを指していますが、以前はmysql:5.7.20を指していました。 タグを指定しないとlatestというタグを指定したとみなされます。

リポジトリを管理しているサービスをレジストリと呼びます。 MySQLやRedisなどの主要なプロダクトの公式イメージは Docker Hub というレジストリで配布されており、 上記の例ではDocker Hub上のリポジトリからイメージを取得しています。 Docker Hub上のリポジトリは下記のページで探すことができます。

https://hub.docker.com/explore/

Docker Hub以外のレジストリを使う場合は下記のようにリポジトリの前にレジストリのホスト名とポート番号を書きます。 例えばローカルレジストリ myregistry.local:5000 から testing/test-image を取得する場合は下記のようになります。

$ docker image pull myregistry.local:5000/testing/test-image

docker image ls (docker images): イメージの一覧を表示する

持っているイメージの一覧を表示します。

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
mysql               5.7.21              5195076672a7        3 weeks ago         371MB

docker image rm (docker rmi): イメージを削除する

docker image ls で表示された IMAGE ID を指定します。

$ docker image rm 5195076672a7
Untagged: mysql:5.7.21
Untagged: mysql@sha256:691c55aabb3c4e3b89b953dd2f022f7ea845e5443954767d321d5f5fa394e28c
Deleted: sha256:5195076672a7e30525705a18f7d352c920bbd07a5ae72b30e374081fe660a011
Deleted: sha256:bc52f6d08bc65c22baab4384ae534d4c5ba8c988197de49975e0a0f78310dd89
Deleted: sha256:b2590548a0917767b420cf20d0cef3aae8912314de216f624c0840f3ad827aa7
Deleted: sha256:756d63a7d5896b52d445ea84ee392cb08a7c119322cfcdfed6303de1ed0d0eab
Deleted: sha256:8e4736576db75536185beba95c5877deeb3915740688cbbc17fe04aed3632282
Deleted: sha256:e6e6e1bb8a16eadbe6628770767615fbc8d67bf11dde69a902116efe847baa7e
Deleted: sha256:080b6c4ec1d55d91a7087e12ae3bd4df252148d94f9911209e0a83d50dc63784
Deleted: sha256:58b97da9f98f75af01ae59c3cb1fdd07a07297015459f3f9f88b140699b29147
Deleted: sha256:3918448e7fe95f36f67a55c938559bab787249b8fa5c7e9914afd46994d045b0
Deleted: sha256:fac8373d1ec4f5bb6c13f12170f558edc3cfbfe8215ae3d1c869940401bc14cf
Deleted: sha256:130f3e567e288fdbbc3ae7cd7aa6c8b3d952bebd3eae58f0a7da93acbb22a258
Deleted: sha256:3358360aedad76edf49d0022818228d959d20a4cccc55d01c32f8b62e226e2c2

docker container run (docker run): コンテナを起動する(シェル編)

docker container runコマンドを使います。下記のようなフォーマットです。

$ docker container run [OPTIONS] IMAGE [COMMAND] [ARGS...]

指定したIMAGEで新しいコンテナを起動し、COMMANDを実行します。ARGSはCOMMANDに対する引数です。

COMMANDを省略した場合は、そのイメージに定義されたデフォルトのコマンドが実行されます。

mysql:5.7.21 イメージでbashを実行する場合は下記のようにします。

$ docker container run -it --rm mysql:5.7.21 /bin/bash

オプションはそれぞれ下記のような意味です。

  • -it: シェルのような対話型のCLIコマンドを起動する場合に指定します。
  • --rm: プロセス終了時にコンテナを削除したい場合に指定します。(指定しないとコンテナの残骸が残ります)

-i-tは別々のオプションですが、セットで指定することが多いオプションです。詳細はリファレンスで確認してください。

なお、指定したイメージがない場合は自動的にレジストリからダウンロードされるため、事前にdocker image pullを実行する必要はありません。

docker container run (docker run): コンテナを起動する(mysqld編)

mysql:5.7.21 イメージでコンテナを起動し、ローカルから接続してみます。

$ docker container run --rm -d -p 3306:3306 -v $(pwd)/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=mysql --name db1 mysql:5.7.21
40a551e33878d12c0c2fff330e6af0ad487be2235919a49ebc29dd4c084ddcf1

表示されたのはCONTAINER IDです。後述するコンテナへの操作を行う際には、このIDか--nameで指定した名前を指定します。 今回はCOMMANDを指定していないので、自動的にmysqldコマンドが実行されます。 mysqlイメージの内容については Docker HubのmysqlのページにあるDockerfileへのリンクで確認できます。

オプションはそれぞれ下記のような意味です。

  • --rm: プロセス終了時にコンテナを削除したい場合に指定します。(指定しないとコンテナの残骸が残ります)
  • -d: コンテナをバックグラウンドで起動します。
  • -p 3306:3306: コンテナのポートをホスト側のポートにマッピングします。左側がホスト側のポートです。
  • -v $(pwd)/data:/var/lib/mysql: ホスト側のパスをコンテナ上のパスにマッピングします。左側がホスト側のパスで、絶対パスで指定する必要があります。
  • -e MYSQL_ROOT_PASSWORD=mysql: 環境変数を追加してコンテナを起動します。
  • --name db1: コンテナの名前です。省略するとランダムな値が自動的に与えられます。

MYSQL_ROOT_PASSWORDのように、イメージによっては環境変数を指定することでコンテナの動作を変えることができる場合があります。 mysqlイメージにおける環境変数の仕様は このページEnvironment Variables以下に書かれています。 大体の場合はDocker Hubのリポジトリのページに説明があります。

-vオプションは、Data Volumeの指定に使います。 コンテナを削除するとコンテナに書き込まれたデータは全て削除されますが、 データベースのようなプロダクトではそれだと困るので、永続化データをコンテナの外部に持つ仕組み(Data Volume)があります。 今回のケースではホスト側のカレントディレクトリ以下のdata/というディレクトリをコンテナ上の/var/lib/mysql/にマウントしています。 mysqlイメージのデフォルト設定では/var/lib/mysql/はMySQLのデータディレクトリなので、 ホスト側でdata/ディレクトリを削除しない限り、コンテナを削除しても同じパスにマウントしてまたコンテナを起動すればデータベースの内容を維持できます。 Data Volumeの詳細については下記のドキュメントを参照してください。

なお、起動したコンテナ上のmysqldには下記のコマンドで接続できます。(mysqlコマンドがない場合、brew install mysqlでインストールできます)

$ mysql --host 127.0.0.1 -uroot -pmysql

docker container ls (docker ps): コンテナの一覧を取得する

$ docker container ls -a
CONTAINER ID        IMAGE               COMMAND                  CREATED                  STATUS              PORTS                    NAMES
40a551e33878        mysql:5.7.21        "docker-entrypoint.s…"   Less than a second ago   Up 2 seconds        0.0.0.0:3306->3306/tcp   db1

-a オプションは停止中のコンテナも表示するという意味です。

docker container exec (docker exec): 起動中のコンテナで別のコマンドを実行する

CONTAINER IDまたはdocker container runでコンテナを起動するときに--nameオプションで指定した名前でコンテナを指定します。 以下の例では、先ほどバックグラウンドで起動したmysqlコンテナでbashを起動し、ターミナルからmysqladminコマンドを実行しています。 オプションの -it の意味は docker container run と同じです。

% docker container exec -it db1 /bin/bash
root@40a551e33878:/# mysqladmin status -pmysql
mysqladmin: [Warning] Using a password on the command line interface can be insecure.
Uptime: 43  Threads: 1  Questions: 4  Slow queries: 0  Opens: 105  Flush tables: 1  Open tables: 98  Queries per second avg: 0.093
root@40a551e33878:/# exit

docker container logs (docker logs): コンテナのログを取得する

docker container logsコマンドを使うと、BG実行したコンテナのログを端末に表示できます。 CONTAINER IDまたはdocker container runでコンテナを起動するときに--nameオプションで指定した名前でコンテナを指定します。

$ docker container logs -f db1
(省略)
2018-04-08T05:04:39.040525Z 0 [Note] Event Scheduler: Loaded 0 events
2018-04-08T05:04:39.041069Z 0 [Note] mysqld: ready for connections.
Version: '5.7.21'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)

-f(--follow)オプションを指定すると、コンテナのSTDOUTとSTDERRから新しい出力があれば表示し続けます。

docker container rm (docker rm): コンテナを削除する

CONTAINER IDまたはdocker container runでコンテナを起動するときに--nameオプションで指定した名前でコンテナを指定します。

# コンテナの停止
$ docker container stop db1

# コンテナの削除
$ docker container rm db1

または

# コンテナを停止して削除
$ docker container rm -f db1

参考情報

より詳細な使い方は下記のドキュメントを参照してください。

また、対応しているバージョンが少し古いですが、日本語化されたドキュメントもあります。

次回は Docker Compose/Dockerfile編 です。おすすめの書籍もこちらで紹介しています。