Docker SwarmでGo Appを動かすときログをファイルに吐き出しても、コンテナ内部のファイルに吐き出しているだけで、dockerのscratchイメージベースに作られているイメージはそもそもShellはない、ログをホストに出したいので、docker servce createコマンドに--mountオプションを使って、コンテナの中のファイルとホストのファイルを紐づくことができる。
結論からいうとしたのコマンドで
docker service create --replicas 2 --env ATHENA_ENV=dev --name athena -p 3000:3000 --mount type=bind,source=/var/log/athena/console.log,destination=/console.log dg-general-use.objectstorage.cloud.egg.jp:5000/athena:1.2.3
事前にDocker Swarmの各ホストに/var/log/athena/console.logファイルを作成する必要がある。
これでコンテナはどのホストにスケジューリングされても大丈夫。
--mount type=bind,source=/file/in/host,destination=/file/in/container
イメージを変えずにAppをUpdateしたいときに--mount-addオプションを使うと強制的にアップデートができる
docker service update <app-name> --replicas 2 --mount-add type=bind,source=/var/log/athena/console.log,destination=/another/dir/console.log --image example.com:5000/athena:1.2.3
これでコンテナはローリングアップデートされる。
似ているようなオプションは--env, --env-add、--env-rmもある。
上の例ではmountするタイプはbindになっているが、data volumeをbindする(type=volume,source=...,destination=...)こともできる。
Docker Swarmの中にGo Appを動かすときにできるだけGo Appイメージのサイズを小さくしたい。
イメージをBuildするときにCentosを指定して、なんの不自由もなかったが、GoのBinaryを動かすだけで、Centos中の不要なファイルついてきて、コンテナの起動にオーバーヘッドをもたらすだけ。イメージを作成すると200Mを超えてしまう。
FROM centos:7
RUN mkdir /app
ADD athena /app
CMD ["./athena"]
なので、DockerのScratchイメージからBuildできるかを調べていた。athenaアプリの中にタイムゾーンを設定する必要があるため
zoneinfoファイルが必要
https関連の通信も発生する可能性が高いため、
- Trust storeルート証明証関連のファイルも必要
結論からいうと、下のようなDockerfileになる。
FROM scratch
ADD config/ca-certificates.crt /etc/ssl/certs/
ADD config/zoneinfo.tar.gz /
ADD athena /
ADD config/app.toml /
WORKDIR /
CMD ["/athena"]
scratch自体のサイズは0 byte、shellもないので、コンテナ立ち上げても、docker exec -it <container-id> /bin/bashで入れない。
Trust Storeルート証明書ca-certificates.crtは Mozillaのデータをダウンロードする
curl -o ca-certificates.crt https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt
タイムゾーンの情報zoneinfo.tar.gzはCentos VMに入って、取ってくる
tar cfz zoneinfo.tar.gz /usr/share/zoneinfo
これらの情報は取得してきたらGoのAppをbuildするときに静的コンパイルが必要で、必要なファイルは全部バイナリに入れて、Gun Libraryを依存しないようにする。
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -a -ldflags '-s' -installsuffix cgo -o athena main.go
このコンパイルが終わると、動的実行ファイルでなければいい
$ ldd athena
動的実行ファイルではありません
これで外部環境でコンパイルしたバイナリをイメージに入れてサイズを200Mから10Mに減らすことができる
MongoDBコンテナ
MongoDBのデータはData Volumeに保存する
MongDBのインスタンスを起動するときにData VolumeをMountするようにする。
MongoDBがコンテナの/data/dbに保存されているデータは全部ローカルマシンの/mnt/general-use/docker-mongodb-dataに永久保存されます。他のディレクトリに保存されているデータはコンテナが削除されるとローカルマシンからも消える
$ docker create --name mongo-data --volumes /mnt/general-use/docker-mongodb-data:/data/db centos
$ docker run -d --volumes-from mongo-data --name mongo -p 27017:27017 mongo
8d2181dd25affd60e1596e8cccdf8031692a1d795ceffd644d32bad96dbe8666
Private Docker RegistryにBasic認証を適応
mkdir auth
docker run --entrypoint htpasswd registry:2 -Bbn testuser testpassword > auth/htpasswd
docker run -d -p 5000:5000 --restart=always --name registry -v `pwd`/private-docker-registry/certs:/certs -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/fullchain.pem -e REGISTRY_HTTP_TLS_KEY=/certs/privkey.pem -v `pwd`/private-docker-registry/auth:/auth
-e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd -v /mnt/general-use/private-docker-registry/data/:/var/lib/registry registry:2
Private Docker RegistryにPush
http://stackoverflow.com/questions/28349392/how-to-push-a-docker-image-to-a-private-repository
docker tag redis dg-general-use.objectstorage.cloud.egg.jp:5000/redis
docker push dg-general-use.objectstorage.cloud.egg.jp:5000/redis
サービスathenaをローリングアップデートして、新しいimage 1.1を使うように
$ docker service update athena --image wzj8698/athena:1.1
Run swarm join-token --rotate to invalidate the old token and generate a new token. Specify whether you want to rotate the token for worker or manager nodes:
docker swarm join-token --rotate worker
docker swarm join-token --rotate manager
Docker SwarmのTokenを調べる
docker swarm join-token --quiet worker
docker swarm join-token --quiet manager
docker-machine の各種コマンド実行時に TLS 接続エラーになったら
Unable to query docker version: Get https://192.168.99.102:2376/v1.15/version: x509: certificate is valid for 192.168.99.101, not 192.168.99.102
docker-machine regenerate-certs <hostname>
docker volumeを作成して、 data というvolumeを利用しているコンテナは /tmpディレクトリへの書き込みだけは消えない
$ docker create --name data --volume /tmp ubuntu
$ docker run -it --name i1 --volumes-from data ubuntu /bin/bash
# echo "abc" > /tmp/aaa # 消えない
# echo "cde" > /home/bbb # 消える
wget https://download.docker.com/mac/stable/Docker.dmg
wget https://github.com/docker/toolbox/releases/download/v1.12.0/DockerToolbox-1.12.0.pkg
$ wget https://github.com/docker/machine/releases/download/v0.7.0/docker-machine-`uname -s`-`uname -m`
$ sudo mv docker-machine-`uname -s`-`uname -m` /usr/local/bin/docker-machine
$ sudo chmod +x /usr/local/bin/docker-machine
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum makecache fast
sudo yum list docker-ce.x86_64 --showduplicates |sort -r
sudo yum install docker-ce
現在のユーザーが普通権限でdockerを操作できるように
sudo groupadd docker
sudo gpasswd -a ${USER} docker
Runningになっているコンテナーにはいる
docker exec -it d387fb450fc5 bash
$ docker run -d -P --name static-site prakhar1989/static-site
d3157304e269975ba5d7bf6a8024db4d13366e0c5d1d5157f644354b7d23c212
-d will detach our terminal,
-P will publish all exposed ports to random ports and finally
--name corresponds to a name we want to give.
Centosでdocker runを実行する時に下のエラーをでることがあります
Usage of loopback devices is strongly discouraged for production use.
Either use `--storage-opt dm.thinpooldev` or use `--storage-opt dm.no_warn_on_loop_devices=true` to suppress this warning.
この場合は/etc/sysconfig/docker-storageを下のように修正、dockerを再起動sudo systemctl restart docker.service
DOCKER_STORAGE_OPTIONS="--storage-opt dm.no_warn_on_loop_devices=true"
実際にこのエラーを抑制しないほうがいいので、ここを参照
http://stackoverflow.com/questions/31620825/warning-of-usage-of-loopback-devices-is-strongly-discouraged-for-production-use
立ち上がったコンテナのportをチェックする
$ docker port static-site
443/tcp -> 0.0.0.0:32768
80/tcp -> 0.0.0.0:32769
$ curl http://localhost:32769/
ローカルホストの8888番ポートにアクセスするとdocker container の80番ポートにリクエストが行く, containerの名前はweb_test
docker run -d --name web_test -p 8888:80 docker.io/nginx
The bridge network is the network in which containers are run by default.
$ docker network ls
NETWORK ID NAME DRIVER
3333d28c4c2c bridge bridge
a44766c8c8dc host host
06a72a5cb34c none null
172.17.0.3 and 172.17.0.2is the IP address this container has been allotted.
$ docker network inspect bridge
[
{
"Name": "bridge",
"Id": "3333d28c4c2c76b490ded17e9c281b9b76f5026824fccb681ab5a26f90f737cc",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
...
docker runに--rmオプションをつけるという意味はcontainerがexitすると、container自体はclean upされる。
docker ps -aで確認することができる。一回だけのコマンドを打つときに便利。
docker run -it --rm hello-world
すでに起動されているDocker Containerにアタッチして、入ることができる
$ docker run -it --name tmp_elixir elixir /bin/bash
root@58836313c3a0:/# exit
$ docker start tmp_elixir
$ docker attach tmp_elixir
FROM centos:7
RUN yum -y update && yum clean all
# OSを日本語にする
RUN yum reinstall -y glibc-common && yum clean all
ENV PATH /usr/local/elixir/bin:$PATH
ENV LANG jp_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
RUN unlink /etc/localtime
RUN ln -s /usr/share/zoneinfo/Japan /etc/localtime
RUN yum install -y wget unzip epel-release
# Install Erlang
RUN wget http://packages.erlang-solutions.com/erlang-solutions-1.0-1.noarch.rpm
RUN rpm -Uvh erlang-solutions-1.0-1.noarch.rpm
RUN yum install -y erlang
# Install Elixir
RUN wget https://github.com/elixir-lang/elixir/releases/download/v1.2.5/Precompiled.zip
RUN mkdir -p /usr/local/elixir
RUN cd /usr/local/elixir && unzip /Precompiled.zip
# Install hex & rebar
RUN mix local.hex <<< 'Y'
RUN mix local.rebar <<< 'Y'
Dockerfileをbuild
docker build -t wzj8698/elixir:latest .
docker imagesのヘルプを
docker help images
同一ホスト上のコンテナ間で通信する際に、接続したい相手のネットワーク情報(IPアドレスなど)を取得する仕組み。次の2つの形で情報を取得できる。
- 環境変数
- /etc/hosts ファイル
docker run -d -p 80:80 -p 11111:22222 --name Container1 centos ping localhost
次に、接続元のコンテナを --link オプションを使って起動する。--link は、<接続先コンテナ名:エイリアス名>という形式で指定する。
docker run -it --name Container2 --link Container1:c1 centos /bin/bash
接続元コンテナ内から環境変数を表示すると、エイリアス名のついた環境変数が作られて、接続先の情報が入っていることが分かる。
[root@2c578037be18 /]# env | grep C1 | sort
C1_NAME=/Container2/c1
C1_PORT=tcp://172.17.0.2:80
C1_PORT_22222_TCP=tcp://172.17.0.2:22222
C1_PORT_22222_TCP_ADDR=172.17.0.2
C1_PORT_22222_TCP_PORT=22222
C1_PORT_22222_TCP_PROTO=tcp
C1_PORT_80_TCP=tcp://172.17.0.2:80
C1_PORT_80_TCP_ADDR=172.17.0.2
C1_PORT_80_TCP_PORT=80
C1_PORT_80_TCP_PROTO=tcp
また、/etc/hosts に接続先のエントリが追加される。
[root@2c578037be18 /]# cat /etc/hosts
...
172.17.0.2 c1 c4adca15a85d Container1
172.17.0.3 2c578037be18
もう一つredisを使った例でredisイメージを使ったclient1とclient2がredis1サーバーに繋がる.client1から定義した変数myvarがclient2で取得する
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
855611bf2296 redis "docker-entrypoint.sh" 48 seconds ago Up 47 seconds 6379/tcp client2
eea6e2df7309 redis "docker-entrypoint.sh" 2 minutes ago Up 2 minutes 6379/tcp client1
ba13188b1ec1 redis "docker-entrypoint.sh" 8 minutes ago Up 8 minutes 6379/tcp redis1
docker pull redis
docker run -d --name redis1 redis # redisサーバー
docker run -it --link redis1:redis-server --name client1 redis sh # client1
# redis-cli -h redis-server
redis-server:6379> PING
PONG
redis-server:6379> set myvar DOCKER
OK
redis-server:6379> get myvar
"DOCKER"
docker run -it --link redis1:redis-server --name client2 redis sh # client2
# redis-cli -h redis-server
redis-server:6379> get myvar
"DOCKER"
docker createコマンドはコンテナーをつくるけど、起動しない
$ docker create --cidfile /tmp/web.cid nginx
6c463befb325be315a831f9047684a188fff787bada2064cd5af2da5a91d3e0b
$ cat /tmp/web.cid
6c463befb325be315a831f9047684a188fff787bada2064cd5af2da5a91d3e0b
$ docker ps --latest --quiet # 最後に起動したコンテナのidだけを表示
6c463befb325
$ docker ps --latest --quiet --no-trunc
6c463befb325be315a831f9047684a188fff787bada2064cd5af2da5a91d3e0b
inspectでみてみると起動していないことが分かる
$ docker inspect --format "{{.State.Running}}" 6c463befb325be315a831f9047684a188fff787bada2064cd5af2da5a91d3e0b
false
startさせる
$ docker start 6c463befb325be315a831f9047684a188fff787bada2064cd5af2da5a91d3e0b
if you’re experimenting with short-lived containers, you can avoid the cleanup burden by specifying --rm on the command. Doing so will automatically remove the container as soon as it enters the exited state.
$ docker run --rm --name auto-exit-test busybox:latest echo Hello World
Hello World
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
-v, --volumes Remove the volumes associated with the container
$ docker rm -vf cass1
This command mounts the host directory, /src/webapp, into the container at /opt/webapp. If the path /opt/webapp already exists inside the container’s image, the /src/webapp mount overlays but does not remove the pre-existing content. Once the mount is removed, the content is accessible again.
$ docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py
コンテナの終了コード(exit)と(status)にたいしてフィルタ可能、statusはrunning, exited, paused, created
$ docker ps -a --filter "status=exited"
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ee0dbdb52fe7 cassandra:2.2 "/docker-entrypoint.s" 24 hours ago Exited (143) 24 hours ago cass1
0b6c442d891a alpine "echo Data Container" 24 hours ago Exited (0) 24 hours ago cass-shared
$ docker ps -a --filter "status=running"
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0a251dcf7f57 object-storage/mysql "/sbin/init" 6 hours ago Up 6 hours 0.0.0.0:3306->3306/tcp mysql-object-storage
$ docker ps -a --filter "exited=143"
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ee0dbdb52fe7 cassandra:2.2 "/docker-entrypoint.s" 24 hours ago Exited (143) 24 hours ago cass1
jsonの形でコンテナの情報を出力
$ docker inspect --format='{{json .State}}' mysql-object-storage
{"Status":"running","Running":true,"Paused":false,"Restarting":false,"OOMKilled":false,"Dead":false,"Pid":3771,"ExitCode":0,"Error":"","StartedAt":"2016-06-10T00:27:41.55468633Z","FinishedAt":"0001-01-01T00:00:00Z"}
動いているコンテナにたいして変更をした後にコミットすることができる
$ docker commit mysql-object-storage mysql-test:1.0
sha256:02a957b83f21d3fa853d511f0a6ca0db40ed676232a956925752f8a82ae5ee36
docker ps -aの結果の中のコンテナんの名前をかえる
$ docker rename condescending_roentgen new_name
コンテナにhostnameをつけて実行する
$ docker run --rm --hostname barker alpine:latest nslookup barker
Name: wow
Address 1: 172.17.0.3 wow
nslookup: can't resolve '(null)': Name does not resolve
コンテナに使われるDNSサーバーを指定する
$ docker run --rm --dns 8.8.8.8 --name dns_test -it busybox
/ # nslookup google.com
Server: 8.8.8.8
Address 1: 8.8.8.8 google-public-dns-a.google.com
Name: google.com
Address 1: 2404:6800:4004:814::200e nrt13s37-in-x0e.1e100.net
Address 2: 216.58.220.238 nrt13s37-in-f14.1e100.net
$ docker run -it --name image-dev ubuntu:latest /bin/bash
# apt-get update
# apt-get install git -y
# exit
image-devへの変化を見てみると
$ docker diff image-dev
C /var/log/alternatives.log
C /var/log/apt
C /var/log/apt/history.log
A /var/log/apt/term.log
C /var/log/dpkg.log
もう一例
$ docker run --name tweak-d busybox:latest rm /bin/vi
$ docker diff tweak-d
C /bin
D /bin/vi
ローカルホストの~/docker-nginx/htmlディレクトリにウェブページを用意して、立ち上がったnginxがコンテナがそれを使うように
$ docker run --name nginx-blog -p 80:80 -d -v ~/docker-nginx/html/blog/_site:/usr/share/nginx/html nginx
既存のイメージ ubuntu-gitを新しいタグをつける
$ docker tag ubuntu-git wzj8698/git:version1.0
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu-git latest 1df63ab69570 2 days ago 254.1 MB
wzj8698/git version1.0 1df63ab69570 2 days ago 254.1 MB
$ docker rmi 1df63ab69570
Error response from daemon: conflict: unable to delete 1df63ab69570 (must be forced) - image is referenced in one or more repositories
イメージimage-devから新しいイメージをコミットする
docker run -it --name image-dev ubuntu:latest /bin/bash
...
docker commit -a "@name-of-the-author" -m "Commit message" image-dev ubuntu-git
# curl -L https://github.com/docker/compose/releases/download/1.9.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose
docker-compose.ymlファイルを作成した後にdocker-compose up -dを実行する。-dオプションはdaemonとして実行するという意味。
http://localhost:8080/にアクセスするとwordpressが表示される。
web:
image: wordpress
links:
- mysql
environment:
- WORDPRESS_DB_PASSWORD=sample
ports:
- "127.0.0.1:8080:80"
mysql:
image: mysql:latest
environment:
- MYSQL_ROOT_PASSWORD=sample
- MYSQL_DATABASE=wordpress
コンテナをチェックしてみる。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
21d845162235 wordpress "/entrypoint.sh apach" 5 minutes ago Up 12 seconds 127.0.0.1:8080->80/tcp wordpress_web_1
f3d5607883bf mysql:latest "docker-entrypoint.sh" 8 minutes ago Up 13 seconds 3306/tcp wordpress_mysql_1
docker-machineでバーチャルホストを作成
$ docker-machine create --driver virtualbox host1
Creating CA: /Users/a21032773/.docker/machine/certs/ca.pem
Creating client certificate: /Users/a21032773/.docker/machine/certs/cert.pem
Running pre-create checks...
(host1) Image cache directory does not exist, creating it at /Users/a21032773/.docker/machine/cache...
...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env host1
$ docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
host1 - virtualbox Running tcp://192.168.99.100:2376 v1.11.2
machine1をactiveにする
$ eval "$(docker-machine env machine1)"
動いているあるいは停止しているコンテナをtarファイルにexportして、さらにできたtarファイルをimportすると、新しいimageができる
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d387fb450fc5 nginx "nginx -g 'daemon off" 3 weeks ago Up 8 days 0.0.0.0:80->80/tcp, 443/tcp nginx-blog
$ docker export d387fb450fc5 > docker_image.tar
$ cat docker_image.tar | docker import - another_image
sha256:f8d9f47f26543bea97217ae0ff8b98af9d5731bc151eb95abc386910b0d78557
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
another_image latest f8d9f47f2654 12 seconds ago 181.2 MB
外からMysqlコンテナにSQLファイルをRestore。-iオプションだけを使えばいい。
$ docker exec -i db mysql -uroot -pexample wordpress < dump.sql
swarmイメージをpullしてくる。
$ docker run swarm --help
When defining any service in docker-compose.yml, you can declare that you are extending another service like this:
web:
extends:
file: common-services.yml
service: webapp
This instructs Compose to re-use the configuration for the webapp service defined in the common-services.yml file. Suppose that common-services.yml looks like this:
webapp:
build: .
ports:
- "8000:8000"
volumes:
- "/data"