Docker と Docker Compose 備忘録


Posted on Wed, Mar 20, 2024
Tags docker, container, docker-compose

Docker について備忘録をまとめる

docker コマンドについて

イメージ、コンテナへの操作

docker tag で名前を変更する

build などしてイメージが hash 担っているケースで名前をわかりやすくつけたい場面がある。tag を使うしかなさそう?

Docker イメージの働き - Qiita

docker build .
docker tag 09134185310 myapp:latest

docker file からファイルをコピーしてくる

docker create --name temp-image some-image
docker cp temp-image:/some/dir/file.tmp file.tmp
docker rm temp-image

コンテナ実行

docker run = docker create & docker start

run はコンテナを作成して、起動する。このとき、 -d の dettach を行うとそのままプロセスがバックグラウンドで走り続ける。 -i はコンテナから exit したらコンテナを落とす

Docker Documentation

privileged を付けるとで何でもできる特権 container になる

docker run --it alpine:latest --privileged

docker exec は実行中の docker process でコマンド実行

docker exec -it <コンテナ名> で docker で現在実行中のプロセス(ただし、PATH に shell がある)に入ることができる。

docker ps -a で停止しているプロセスも含めてすべて閲覧

sudo docker ps -a

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
71e0cf6a50a6        101779243274        "/bin/bash"         5 weeks ago         Exited (137) 2 weeks ago                       angry_fermat
d5577c8aca3f        bbe77145eb18        "/bin/bash"         5 weeks ago         Exited (137) 2 weeks ago                       eager_carson
b8c0b1a734a6        101779243274        "bash"              6 weeks ago         Up 8 days                                      interesting_shtern
3ce1af5ce44c        bbe77145eb18        "/bin/bash"         8 weeks ago         Exited (137) 2 weeks ago                       hardcore_torvalds
0456af55e878        bbe77145eb18        "/bin/bash"         2 months ago        Exited (137) 2 weeks ago                       lucid_swanson

イメージ、コンテナのクリーンアップ

TAG が none の image 削除

docker image prune

docker 1.25 から利用ができるようだ。それまでは下記のように複数のコマンドを使う必要があった。

docker rmi $(docker images -f "dangling=true" -q)

docker でイメージ削除を for で実施する

$ arr=("image_id1" "image_id2" "image_id3"); for i in "${arr[@]}" ; do sudo docker rmi -f $i ; done

docker で exit して止まっているコンテナの削除を行う

docker rm $(docker ps -aq)

で止まっているコンテナの削除ができる。

$(docker ps -aq) は running のものも対象になっているが、 docker rm は running のコンテナは削除しない。

docker run を抜け出したら、コンテナを落とすようにする

docker run --rm -it --name="default" alpine /bin/sh

--rm をつけることで、コマンドから抜け出したらコンテナは落ちるようにできる。 これで、色々と試行錯誤して、docker commit や save を行えば、DockerImageができるので、あとは消すだけで良い。

ヘルプで出てくる中のよく使うコマンド

# 個人的に普段あまりつかわないサブコマンドをコメントアウトする
$ docker -h

Common Commands:
  run         Create and run a new container from an image
  exec        Execute a command in a running container
  ps          List containers
  build       Build an image from a Dockerfile
  pull        Download an image from a registry
# push        Upload an image to a registry
  images      List images
# login       Log in to a registry
# logout      Log out from a registry
# search      Search Docker Hub for images
  version     Show the Docker version information
  info        Display system-wide information

Management Commands:
# builder     Manage builds
  container   Manage containers
# context     Manage contexts
  image       Manage images
# manifest    Manage Docker image manifests and manifest lists
  network     Manage networks
# plugin      Manage plugins
  system      Manage Docker
# trust       Manage trust on Docker images
  volume      Manage volumes

Commands:
  attach      Attach local standard input, output, and error streams to a running container
# commit      Create a new image from a container's changes
  cp          Copy files/folders between a container and the local filesystem
# create      Create a new container
# diff        Inspect changes to files or directories on a container's filesystem
# events      Get real time events from the server
# export      Export a container's filesystem as a tar archive
# history     Show the history of an image
  import      Import the contents from a tarball to create a filesystem image
# inspect     Return low-level information on Docker objects
  kill        Kill one or more running containers
  load        Load an image from a tar archive or STDIN
  logs        Fetch the logs of a container
# pause       Pause all processes within one or more containers
  port        List port mappings or a specific mapping for the container
  rename      Rename a container
  restart     Restart one or more containers
  rm          Remove one or more containers
  rmi         Remove one or more images
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
# start       Start one or more stopped containers
# stats       Display a live stream of container(s) resource usage statistics
# stop        Stop one or more running containers
  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
  top         Display the running processes of a container
# unpause     Unpause all processes within one or more containers
# update      Update configuration of one or more containers
# wait        Block until one or more containers stop, then print their exit codes

docker compose

docker compose コマンドについて

# 起動
docker compose up

# volume を使うと、自動的には削除されない。下記のコマンドを使うと、running ではないコンテナと volume も削除できる
docker system prune --volumes

# docker compose で起動したコンテナを停止、あわせて不要な volume も削除する
docker compose down -v

docker-compose.yml

restart

Container がクラッシュしたときの振る舞い。restart だと必ず再度立ち上げようとする

user

Compose file version 3 reference | Docker Documentation にあるとおり、これは docker run の USER に値する。 そして、これは User の UID や username を指定できる

depends_on

起動順序の定義が行える。終了時は逆順となる。 特に web が db に依存する場合は、depends_on: [ db ] のようになることが多い。

ちなみに、web から db へアクセスしたいとき、db:5432 のように指定することで名前解決ができる。

services:
  db:
    image: postgres:15
    environment:
      POSTGRES_DB: dev
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
    ports:
      - 5432:5432

  django:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    environment:
      # host名は docker で起動された db となる
      DATABASE_URL: "postgres://postgres:postgres@db:5432/dev"
      SECRET_KEY: "sample_secret_key"
    volumes:
      - .:/djangoapp
    ports:
      - "8000:8000"
    depends_on:
      - db

docker の仕組み

docker のネットワーク

Docker のネットワークはよくハマる。

Docker compose ではアプリケーション一つに対して、ネットワークを作成する。 各コンテナ上のサービスはデフォルトネットワークに参加したら、同一ネットワーク上の他のコンテナから接続できるようになります。また、ホスト名とコンテナ名でも発見可能になります。

network driver

Driver には、bridge か overlay が指定できる。デフォルトでは bridge

bridge ネットワークとは

「docker0 に値する」とあるが、どういう意味だ……

Use bridge networks | Docker Documentation

A bridge network is a Link Layer device which forwards traffic between network segments. A bridge can be a hardware device or a software device running within a host machine’s kernel.

ネットワークセグメント間で通信を転送する Link layer device とある。 Docker は software bridge を使っていて、定義された bridge network 内につながっているコンテナはお互いに通信が行える。

bridge モードのときは、同じ docker daemon を利用しているコンテナは同じ bridge network になる

異なる daemon 間で通信したい場合は、OS などの設定でルーティングさせるか、overlay ネットワークを使うらしい。

ブリッジ接続 (bridge connection)とは|「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典

Use bridge networks | Docker Documentation

The default bridge network is considered a legacy detail of Docker and is not recommended for production use. Configuring it is a manual operation, and it has technical shortcomings.

デフォルトの bridge network はレガシーとある。

daemon.json で docker daemon が利用する bridge network の設定が記載されている。

To configure the default bridge network, you specify options in daemon.json. Here is an example daemon.json with several options specified. Only specify the settings you need to customize.

{
  "bip": "192.168.1.5/24",
  "fixed-cidr": "192.168.1.5/25",
  "fixed-cidr-v6": "2001:db8::/64",
  "mtu": 1500,
  "default-gateway": "10.20.1.1",
  "default-gateway-v6": "2001:db8:abcd::89",
  "dns": ["10.20.1.2","10.20.1.3"]
}

192.168.1.0 - 192.168.1.255 のレンジを利用しているようだ。

user define bridge で通信

Containers connected to the same user-defined bridge network automatically expose all ports to each other, and no ports to the outside world. This allows containerized applications to communicate with each other easily, without accidentally opening access to the outside world.

同じ bridge network では全てのポートがお互いに通信できるが、外の世界からはポートが空いていないように見える

Dockerfile の書き方

作り方の参考資料

ADD はレイヤーが増えるが、 COPY はレイヤーを増やさない

docker image のファイルサイズを小さくする

go の src に vendor があるのでサイズは大きくなる。でも /go/bin が使われるだけなので、/go/src はまとめて不要 (- 300MB)

[root@7a4baa5582f7 /]# du -sh /go/bin/* | sort -h
3.7M    /go/bin/yaml-patch
13M     /go/bin/om
28M     /go/bin/bosh-cli
[root@7a4baa5582f7 /]# du -sh /go/src/* | sort -h
2.2M    /go/src/gopkg.in
31M     /go/src/golang.org
299M    /go/src/github.com

/usr/local/go は go 言語をインストールしたため、存在するが、image build 後は go は叩かないので不要(go の binary は作られているため) (- 300 MB)

[root@7a4baa5582f7 /]# du -sh /usr/local/go/* | sort -h
6.5M    /usr/local/go/api
12M     /usr/local/go/test
31M     /usr/local/go/bin
75M     /usr/local/go/src
214M    /usr/local/go/pkg

/usr/lib 内は python, jvm でそもそもの動作に必要なので、削除できない

5.7M    /usr/lib/udev
9.1M    /usr/lib/systemd
155M    /usr/lib/python2.7
166M    /usr/lib/jvm

yum の cache も不要 (- 80MB)

[root@7a4baa5582f7 /]# du -sh /var/cache/* | sort -h
16K     /var/cache/ldconfig
81M     /var/cache/yum

multi stage build でどこからでも確実にビルドできるようにする

multi stage を利用するととても便利。dockerfile を build するだけで必要なものを揃えることができる。

  1. make build 方式 <- バイナリのダウンロードなど高速化できるが、make を実行する環境依存
  2. multi stage build <- 環境を整えるのが冗長だが、docker build するだけで済む

multi stage build で ARG を利用する時

ARG JDK_VERSION="15"
ARG PLANTUML_VERSION="1.2020.2"
FROM openjdk:${JDK_VERSION}-jdk-alpine

RUN apk add --update-cache graphviz wget && \
    wget "http://downloads.sourceforge.net/project/plantuml/$PLANTUML_VERSION/plantuml.$PLANTUML_VERSION.jar" 

このコードは動かなくて、ARG は最初の FROM で認識されるにとどまる。正しくは下記のようにする

ARG JDK_VERSION="15"
FROM openjdk:${JDK_VERSION}-jdk-alpine

ARG PLANTUML_VERSION="1.2020.2"
RUN apk add --update-cache graphviz wget && \
    wget "http://downloads.sourceforge.net/project/plantuml/$PLANTUML_VERSION/plantuml.$PLANTUML_VERSION.jar" 

.dockerignore を定義することで、docker image に入れるファイルを制限できる。

.git
**/secret.yaml

と書くことで、どこのフォルダでも除くことができる。.gitignore とやや書式が異なるので注意

この場合、.git フォルダを除かないと git reset でシークレットが復元できたりしてしまうので注意。(そもそもなんで secret 入ってんねんって話だが)