[Docker] docker-composeでRailsの開発環境構築

Dockerfile

FROM ruby:2.3.7

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

RUN mkdir /app

WORKDIR /app

COPY Gemfile /app/Gemfile

COPY Gemfile.lock /app/Gemfile.lock

RUN bundle install

COPY . /app

Gemfile

source 'https://rubygems.org'
gem 'rails', '5.0.0.1'

Gemfile.lockの作成
$ touch Gemfile.lock

docker-compose.yml

version: '3'
services:
  web:
    build: .
    command: bundle exec rails server -p 3000 -b 0.0.0.0
    ports:
      - 3000:3000
    volumes:
      - .:/app
    depends_on:
      - db
    tty: true
    stdin_open: true
  db:
    image: mysql:5.7
    volumes:
      - db-volume:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password
volumes:
  db-volume:

ビルドの実行とRailsプロジェクト作成
$ sudo docker-compose run web rails new . –force –database=mysql
$ ls -la
total 84
drwxrwxr-x 12 vagrant vagrant 4096 Mar 19 02:21 .
drwxr-xr-x 16 vagrant vagrant 4096 Mar 19 01:57 ..
-rw-r–r– 1 root root 468 Mar 19 02:21 .gitignore
-rw-rw-r– 1 vagrant vagrant 211 Mar 19 02:00 Dockerfile
-rw-rw-r– 1 vagrant vagrant 1748 Mar 19 02:21 Gemfile
-rw-rw-r– 1 vagrant vagrant 4430 Mar 19 02:22 Gemfile.lock
-rw-r–r– 1 root root 374 Mar 19 02:21 README.md
-rw-r–r– 1 root root 227 Mar 19 02:21 Rakefile
drwxr-xr-x 10 root root 4096 Mar 19 02:21 app
drwxr-xr-x 2 root root 4096 Mar 19 02:22 bin
drwxr-xr-x 5 root root 4096 Mar 19 02:21 config
-rw-r–r– 1 root root 130 Mar 19 02:21 config.ru
drwxr-xr-x 2 root root 4096 Mar 19 02:21 db
-rw-rw-r– 1 vagrant vagrant 366 Mar 19 02:10 docker-compose.yml
drwxr-xr-x 4 root root 4096 Mar 19 02:21 lib
drwxr-xr-x 2 root root 4096 Mar 19 02:21 log
drwxr-xr-x 2 root root 4096 Mar 19 02:21 public
drwxr-xr-x 8 root root 4096 Mar 19 02:21 test
drwxr-xr-x 3 root root 4096 Mar 19 02:21 tmp
drwxr-xr-x 3 root root 4096 Mar 19 02:21 vendor

$ sudo docker run –rm rails_web ls -la /app
total 20
drwxr-xr-x 1 root root 4096 Mar 19 02:21 .
drwxr-xr-x 1 root root 4096 Mar 19 02:26 ..
-rw-rw-r– 1 root root 211 Mar 19 02:00 Dockerfile
-rw-rw-r– 1 root root 52 Mar 19 02:04 Gemfile
-rw-rw-r– 1 root root 0 Mar 19 02:04 Gemfile.lock
-rw-rw-r– 1 root root 366 Mar 19 02:10 docker-compose.yml

$ sudo docker-compose build
$ sudo docker run –rm rails_web ls -la /app

Railsで使用するデータベースの設定と作成
./config/database.yml

default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: root
  password: password
  host: db

$ docker-compose up
$ sudo docker-compose ps
Name Command State Ports
————————————————————-
rails_db_1 docker-entrypoint.sh mysqld Exit 0
rails_web_1 bundle exec rails server – … Exit 1

$ sudo docker-compose up -d
$ sudo docker-compose ps
Name Command State Ports
———————————————————————————————–
rails_db_1 docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp
rails_web_1 bundle exec rails server – … Up 0.0.0.0:3000->3000/tcp,:::3000->3000/tcp

$ sudo docker-compose run web rake db:create

$ sudo docker-compose run web bin/rails g scaffold User name:string
$ sudo docker-compose run web bundle exec rails db:migrate

### コンテナの停止、削除
$ sudo docker-compose stop
$ sudo docker-compose ps
$ sudo docker-compose down
$ sudo docker-compose up -d

なるほどー
Docker compose使うと複雑になるな…

[docker] docker-compose

アプリケーションのコンテナの他に、データベースなどのコンテナが必要な場合などに使用される

$ sudo docker-compose version
docker-compose version 1.16.1, build 6d1ac21
docker-py version: 2.5.1
CPython version: 2.7.13
OpenSSL version: OpenSSL 1.0.1t 3 May 2016

### docker composeでアプリケーション実行環境を立ち上げる手順
1. コンテナを立ち上げるのに必要なイメージを用意(dockerfile)
2. 各コンテナを起動する際の設定をdocker-compose.ymlに定義
3. docker-compose.ymlに置いてあるディレクトリ上でdocker

– コンテナ間に通信したい場合に、サービス名で通信できる

記述例

version: '3'
services:
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
      - logvolume01:/var/log
  redis:
    image: redis
volumes:
  logvolume01: {}

うおおおおおおおおおお
なんとなくわかってきた

[docker] tmpfsを使ってみる

tmpfsはメモリ領域をコンテナにマウントする
コンテナやホストが停止すると、保持していたデータは解放されtmpfsマウントが取り除かれる

$ sudo docker run -itd –name tmpfs-c1 –mount type=tmpfs,destination=/cache busybox
$ sudo docker inspect tmpfs-c1
“Mounts”: [
{
“Type”: “tmpfs”,
“Source”: “”,
“Destination”: “/cache”,
“Mode”: “”,
“RW”: true,
“Propagation”: “”
}
],

$ sudo docker run -itd –name tmpfs-c1 –mount type=tmpfs,destination=/cache,tmpfs-size=500000000,tmpfs-mode=700 busybox
ファイルモードや容量などを指定できる

なるほど、あんまり使わなそうだな…

[docker] Bind Mount

Bind MountはPC上の任意のディレクトリをコンテナにマウントする
-v <ホスト上のディレクトリ>:<コンテナ上のディレクトリ>

$ touch test-file
$ ls -la
total 8
drwxr-xr-x 2 vagrant vagrant 4096 Mar 19 00:57 .
drwxrwxr-x 3 vagrant vagrant 4096 Mar 18 23:07 ..
-rw-rw-r– 1 vagrant vagrant 0 Mar 19 00:57 test-file

$ sudo docker run -itd –name bind-c1 -v “$(pwd)”:/bind_dir busybox
$ sudo docker exec bind-c1 ls -la /bind_dir
total 8
drwxr-xr-x 2 1000 1000 4096 Mar 19 00:57 .
drwxr-xr-x 1 root root 4096 Mar 19 01:12 ..
-rw-rw-r– 1 1000 1000 0 Mar 19 00:57 test-file
$ touch test-file2
$ sudo docker exec bind-c1 ls -la /bind_dir
total 8
drwxr-xr-x 2 1000 1000 4096 Mar 19 01:13 .
drwxr-xr-x 1 root root 4096 Mar 19 01:12 ..
-rw-rw-r– 1 1000 1000 0 Mar 19 00:57 test-file
-rw-rw-r– 1 1000 1000 0 Mar 19 01:13 test-file2

### -mountを指定したコンテナの起動
$ sudo docker run -itd –name bind-c2 –mount type=bind,source=”$(pwd)”,target=/bind_dir busybox
54deefdb625241544cc84326df8055e38c32a8d3e6b2a97c1d0db2bb260c693f
$ sudo docker exec bind-c2 ls -l /bind_dir
total 0
-rw-rw-r– 1 1000 1000 0 Mar 19 00:57 test-file
-rw-rw-r– 1 1000 1000 0 Mar 19 01:13 test-file2
※–mountオプションの方が読みやすい。また、間違えたディレクトリのバインドを防ぐ意味でも–mountの方が安全

### バインドマウントの設定確認
$ sudo docker inspect bind-c1
“Mounts”: [
{
“Type”: “bind”,
“Source”: “/home/vagrant/dev/docker/test/app”,
“Destination”: “/bind_dir”,
“Mode”: “”,
“RW”: true,
“Propagation”: “rprivate”
}
],

なるほど、bindの概念はvolumeと一緒でわりかし簡単だな

[docker] volumeを作成

### volumeの作成方法
$ sudo docker volume ls
$ sudo docker volume create my-vol
$ sudo docker volume inspect my-vol
[
{
“CreatedAt”: “2022-03-18T23:05:02Z”,
“Driver”: “local”,
“Labels”: {},
“Mountpoint”: “/var/lib/docker/volumes/my-vol/_data”,
“Name”: “my-vol”,
“Options”: {},
“Scope”: “local”
}
]

$ sudo docker volume rm my-vol

### volumeのマウント方法
$ sudo docker run -itd –name c1 -v vol1:/app busybox
$ sudo docker volume ls
$ sudo docker inspect c1

        "Mounts": [
            {
                "Type": "volume",
                "Name": "vol1",
                "Source": "/var/lib/docker/volumes/vol1/_data",
                "Destination": "/app",
                "Driver": "local",
                "Mode": "z",
                "RW": true,
                "Propagation": ""
            }
        ],

$ sudo docker exec -it c1 /bin/sh
/ # df
Filesystem 1K-blocks Used Available Use% Mounted on
overlay 40593612 36988012 3589216 91% /
tmpfs 65536 0 65536 0% /dev
tmpfs 2013052 0 2013052 0% /sys/fs/cgroup
shm 65536 0 65536 0% /dev/shm
/dev/sda1 40593612 36988012 3589216 91% /app
/dev/sda1 40593612 36988012 3589216 91% /etc/resolv.conf
/dev/sda1 40593612 36988012 3589216 91% /etc/hostname
/dev/sda1 40593612 36988012 3589216 91% /etc/hosts
tmpfs 2013052 0 2013052 0% /proc/acpi
tmpfs 65536 0 65536 0% /proc/kcore
tmpfs 65536 0 65536 0% /proc/keys
tmpfs 65536 0 65536 0% /proc/timer_list
tmpfs 65536 0 65536 0% /proc/sched_debug
tmpfs 2013052 0 2013052 0% /proc/scsi
tmpfs 2013052 0 2013052 0% /sys/firmware

/ # cd /app
/app # touch hogehoge
/app # exit

$ sudo docker run -itd –name c2 –mount source=vol1,target=/app busybox
$ sudo docker exec -it c2 /bin/sh
/ # ls -la /app/
total 8
drwxr-xr-x 2 root root 4096 Mar 18 23:16 .
drwxr-xr-x 1 root root 4096 Mar 18 23:18 ..
-rw-r–r– 1 root root 0 Mar 18 23:16 hogehoge

おおおお、マウントされてる…

### 既に存在するディレクトリへのvolumeのマウントについて
$ sudo docker run -itd –name c3 –mount source=vol2,destination=/var busybox
$ sudo docker inspect c3
“Mounts”: [
{
“Type”: “volume”,
“Name”: “vol2”,
“Source”: “/var/lib/docker/volumes/vol2/_data”,
“Destination”: “/var”,
“Driver”: “local”,
“Mode”: “z”,
“RW”: true,
“Propagation”: “”
}
],
$ sudo docker exec -it c3 /bin/sh
/ # ls -la /var/

–mount で読み取り専用(readonly)
-vフラグで読み取り専用

volumeのマウントタイプはDockerホスト上のDockerが管理する領域に自動的にディレクトリが作成されコンテナにマウントされる

なるほど、dockerの管理領域にディレクトリを作成するのがvolumeね。

[Docker] スタンドアローンSwarmのオーバーレイネットワーク

オーバーレイネットワーク: 複数のホストを跨いだネットワーキングに使用されるネットワークドライバ
L ホストのDockerの情報を保存しておくためのキーバリューストアと呼ばれるデータを保持するサーバが必要
L Consul, Etcd, Zookeeperなどがある

TCP port: 2377
TCP/UDP port: 7946
UDP port: 4789

うむ、これはよくわからんわ…

[Docker] ノンネットワークとホストネットワーク

ノンネットワーク: ネットワークインターフェイスを持たない状態にしたい場合に使用するネットワーク
ホストネットワーク: Dockerホストと同じネットワークインターフェースをコンテナで使用したい場合に使用するネットワーク

$ sudo docker network ls
562eb5e84daa none null local … none

$ sudo docker network disconnect my_nw ubuntu1
$ sudo docker network disconnect bridge ubuntu1
$ sudo docker network connect none ubuntu1
$ sudo docker inspect ubuntu1

                "none": {
                    "IPAMConfig": {},
                    "Links": null,
                    "Aliases": [],
                    "NetworkID": "562eb5e84daad5b15117ed125a41d3cffaaf9884095f55949dd92bf1a9533620",
                    "EndpointID": "30ccbdc2f734fede12c9bbd56b4e2b9fa27c0b988b5d7feca224548c4c8622ce",
                    "Gateway": "",
                    "IPAddress": "",
                    "IPPrefixLen": 0,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "",
                    "DriverOpts": {}
                }

ホストネットワークの場合は、ポートフォワーディング設定を行わなくても直にnginxにアクセスできる

なるほど、インフラも奥が深いな…

[Docker] ユーザ定義のブリッジネットワーク作成

デフォルトのブリッジネットワークとユーザ定義のブリッジネットワーク

ubuntuコンテナを起動して詳細を確認します
$ sudo docker run -itd –name ubuntu1 ubuntu /bin/bash

$ sudo docker inspect ubuntu1
L ipアドレスの箇所で 172.17.0.2 が割り当てられている

            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "9d63e39880cdedc5addbd10a11deb3fad9b4679dca150c8ab24c6080a777d0a5",
                    "EndpointID": "d990aa1ffeb44365cc97df34730bf143b2a0b0afbe461fe811b877fca9ad390f",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.2",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:02",
                    "DriverOpts": null
                }
            }

もう一つ同じようにコンテナを作成する
$ sudo docker run -itd –name ubuntu2 ubuntu /bin/bash
$ sudo docker inspect ubuntu2
L ipアドレスの箇所で 172.17.0.3 が割り当てられている

            "Networks": {
                "bridge": {
                    "IPAMConfig": null,
                    "Links": null,
                    "Aliases": null,
                    "NetworkID": "9d63e39880cdedc5addbd10a11deb3fad9b4679dca150c8ab24c6080a777d0a5",
                    "EndpointID": "ea06868987306ff7b8f7419a287d4a8d7282914f2c9746afbe991d9d26e2d657",
                    "Gateway": "172.17.0.1",
                    "IPAddress": "172.17.0.3",
                    "IPPrefixLen": 16,
                    "IPv6Gateway": "",
                    "GlobalIPv6Address": "",
                    "GlobalIPv6PrefixLen": 0,
                    "MacAddress": "02:42:ac:11:00:03",
                    "DriverOpts": null
                }
            }

$ sudo docker exec -ti 77573860f37e /bin/bash
$ apt-get update && apt install iputils-ping
root@77573860f37e:/# ping -c 3 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.079 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.064 ms
64 bytes from 172.17.0.3: icmp_seq=3 ttl=64 time=0.099 ms

— 172.17.0.3 ping statistics —
3 packets transmitted, 3 received, 0% packet loss, time 2027ms
rtt min/avg/max/mdev = 0.064/0.080/0.099/0.014 ms
root@77573860f37e:/# ping -c 3 ubuntu2
ping: ubuntu2: Name or service not known

### コンテナ名で名前解決する方法
$ sudo docker network create my_nw
$ sudo docker network connect my_nw ubuntu1
$ sudo docker network connect my_nw ubuntu2
$ sudo docker exec -ti 77573860f37e /bin/bash
root@77573860f37e:/# ping -c 3 ubuntu2
PING ubuntu2 (172.22.0.3) 56(84) bytes of data.
64 bytes from ubuntu2.my_nw (172.22.0.3): icmp_seq=1 ttl=64 time=0.141 ms
64 bytes from ubuntu2.my_nw (172.22.0.3): icmp_seq=2 ttl=64 time=0.083 ms
64 bytes from ubuntu2.my_nw (172.22.0.3): icmp_seq=3 ttl=64 time=0.068 ms

おおおおおおお

$ sudo docker network ls

Docker基礎2

Dockerコンテナの状態
– created, running, exited, removing, paused, restarting, deadの状態がある

### コンテナへのシェル接続
$ sudo docker run -tid alpine /bin/sh

-tフラグ: 擬似ターミナル(peudo-TTY)を割り当てる
-iフラグ: アタッチされていない状態でも標準入力を保持するためのフラグ
-dフラグ: detachedモードで動作させる場合のフラグ

うむ、なるほど、基礎中の基礎はわかってきた。