Upgrade to Pro — share decks privately, control downloads, hide ads and more …

夜の本気Docker

 夜の本気Docker

2022/07/26 坊村さん勉強会発表資料

More Decks by PharmaX(旧YOJO Technologies)開発チーム

Other Decks in Technology

Transcript

  1. YOJO のDocker について説明しつつ少しDeepDive 1 YOJO のDocker について説明しつつ少し DeepDive 📖 ⽬次

    説明⽤資料↓ https://www.notion.so/yojotechnologies/Docker- 41fb0a0bc8344cc5825220b7db19a0c5#871eca1e1d8e40d8b88d6a516ed19700 YOJO のDocker で説明するDocker のネットワーク YOJO のDocker はそれぞれが密接に連携しています ngrok linebot-service linebot-admin linebot-admin-bff linebot-web linebot-web-bff 例えばlinebot-admin-bff からlinebot-service につなぐには以下のようなURL で接続できます。 http://linebot-service:3000 = http://host.docker.internal:3000 このURL の linebot-service は⼀体何モノでしょうか? これこそがDocker のネットワークを使ったちょっとしたハックです。以下にも書いてあるとおり、 Docker 構築⼿順 このネットワークが実現してくれています。 $ docker network create yojo-shared-network # 確認(network が表⽰されたらOK) $ docker network ls|grep yojo-shared-network xxxxxxxxxxxxxxx yojo-shared-network bridge local YOJO のDocker で説明するDocker のネットワーク Dockerfile のTips Docker compose
  2. YOJO のDocker について説明しつつ少しDeepDive 2 実際にご⾃⾝の利⽤しているDocker でネットワーク構成を⾒てみましょう。 Docker for mac には↓

    のようなNetwork の記述があります。 が、実はこれ「Docker for linux 」でしか機能しません。 後述しますがDocker for mac は内部でHyperkit VM が動いているためです。このVM のOS のnameserver が nameserver 192.168.65.5 とかだったりします。 https://docs.docker.jp/network/host.html Linux では --net=host を使うことで、ホストのネットワーク上にDocker コンテナを⽴ち上げることができるのです。 docker run --net=host xxxx では、Linux 以外はどうすれば良いのでしょうか。実はこれが yojo-shared-network なのです。 どういうネットワーク構成なのかみてみましょう。 docker network ls コマンドで確認可能です。 docker network ls NETWORK ID NAME DRIVER SCOPE
  3. YOJO のDocker について説明しつつ少しDeepDive 3 68216b35848c bridge bridge local 408be66312d6 host

    host local c72632311209 none null local 51babaa5af3c yojo-shared-network bridge local 詳細を⾒るときは docker network inspect を使います。 docker network inspect yojo-shared-network [ { "Name": "yojo-shared-network", "Id": "51babaa5af3ceedcaea3f732ac8e9e00ebe63aafeaca2cdc747bb8954d57900e", "Created": "2022-05-05T11:24:16.961149711Z", "Scope": "local", "Driver": "bridge", "EnableIPv6": false, "IPAM": { "Driver": "default", "Options": {}, "Config": [ { "Subnet": "172.18.0.0/16", "Gateway": "172.18.0.1" } ] }, "Internal": false, "Attachable": false, "Ingress": false, "ConfigFrom": { "Network": "" }, "ConfigOnly": false, "Containers": {}, "Options": {}, "Labels": {} } ] ⼤事な情報が出てきました。 yojo-shared-network は以下のサブネット・ゲートウェイを持った内部ネットワークなのです。 "Subnet": "172.18.0.0/16", "Gateway": "172.18.0.1" 次に yojo-shared-network を使っている linebot-admin-bff と linebot-service の2 つのDocker の詳細情報を⾒てみましょう。ち なみにどちらも docker-compose を使ってコンテナを⽴ち上げた状態でなければだめなので、今回は説明のみやります。 docker inspect yojo-linebot-service [[ { "Id": "3a5a6951f13fa1b862bf13729010837a27157f43894bb3fe5ae28563de3321bd", "Created": "2022-07-25T17:29:14.026113171Z", "Path": "entrypoint.sh", "Args": [ "bash", "-c", "bundle install \u0026\u0026 rm -f tmp/pids/server.pid \u0026\u0026 bundle exec rails s -p 3000 -b '0.0.0.0'" ], "State": { "Status": "running", "Running": true, "Paused": false,
  4. YOJO のDocker について説明しつつ少しDeepDive 4 "Restarting": false, "OOMKilled": false, "Dead": false,

    "Pid": 53158, "ExitCode": 0, "Error": "", "StartedAt": "2022-07-25T17:30:33.571559555Z", "FinishedAt": "2022-07-25T17:29:46.079069047Z" }, "Image": "sha256:b720c21f48181a7fb0ae88443ffce4fb352a97e9e6423d61e9ec464ad0817dac", "ResolvConfPath": "/var/lib/docker/containers/3a5a6951f13fa1b862bf13729010837a27157f43894bb3fe5ae28563de3321bd/resolv.conf", "HostnamePath": "/var/lib/docker/containers/3a5a6951f13fa1b862bf13729010837a27157f43894bb3fe5ae28563de3321bd/hostname", "HostsPath": "/var/lib/docker/containers/3a5a6951f13fa1b862bf13729010837a27157f43894bb3fe5ae28563de3321bd/hosts", 略 ・ ・ ・ "Networks": { "yojo-service_default": { "IPAMConfig": null, "Links": null, "Aliases": [ "yojo-linebot-service", "linebot-service", "3a5a6951f13f" ], "NetworkID": "41e5a517c1355a8a7d48d4c526ef2c8894cdc06751f21e3c503418c3fe4cff9d", "EndpointID": "f0eec92fccda5a1d7afeafb79e726998b025f7ec2412b3092023f2f64063e05c", "Gateway": "172.29.0.1", "IPAddress": "172.29.0.5", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:1d:00:05", "DriverOpts": null }, "yojo-shared-network": { "IPAMConfig": null, "Links": null, "Aliases": [ "yojo-linebot-service", "linebot-service", "3a5a6951f13f" ], "NetworkID": "51babaa5af3ceedcaea3f732ac8e9e00ebe63aafeaca2cdc747bb8954d57900e", "EndpointID": "7ebfc66e1b54567a98a736e7574122b81957af90e772ad76ee85b163be7d146a", "Gateway": "172.18.0.1", "IPAddress": "172.18.0.3", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:12:00:03", "DriverOpts": null } } ⼤量の情報が出てきましたが⼤事なのはここです。 "HostnamePath": "/var/lib/docker/containers/3a5a6951f13fa1b862bf13729010837a27157f43894bb3fe5ae28563de3321bd/hostname", "HostsPath": "/var/lib/docker/containers/3a5a6951f13fa1b862bf13729010837a27157f43894bb3fe5ae28563de3321bd/hosts", "yojo-shared-network": { "IPAMConfig": null, "Links": null, "Aliases": [ "yojo-linebot-service", "linebot-service", "3a5a6951f13f" ],
  5. YOJO のDocker について説明しつつ少しDeepDive 5 "NetworkID": "51babaa5af3ceedcaea3f732ac8e9e00ebe63aafeaca2cdc747bb8954d57900e", "EndpointID": "7ebfc66e1b54567a98a736e7574122b81957af90e772ad76ee85b163be7d146a", "Gateway": "172.18.0.1",

    "IPAddress": "172.18.0.3", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:12:00:03", "DriverOpts": null } yojo-shared-network が出てきました。yojo-linebot-service の内部IP は 172.18.0.3 です。これは yojo-shared-network のサブネッ ト 172.18.0.0/16 内ですね。 ということは… docker inspect yojo-linebot-admin-bff ( 略) "NetworkID": "51babaa5af3ceedcaea3f732ac8e9e00ebe63aafeaca2cdc747bb8954d57900e", "EndpointID": "d9b035872f3dd83198c221b7d55bfae2b76301168720e1cb529c69239cbaf33e", "Gateway": "172.18.0.1", "IPAddress": "172.18.0.2", はい! yojo-linebot-admin-bff も 172.18.0.2 ですね! つまりこの2 つのサービスは、同じ内部IP を持っているので、ホストネットワークを使わずとも相互でネットワーク疎通する ことが可能だということです! ちなみにそして謎の HostnamePath に書かれているパスの中⾝をmac でみようとすると…… '/var/lib/docker/containers/3a5a6951f13fa1b862bf13729010837a27157f43894bb3fe5ae28563de3321bd/hostname': No such file or directory なんとファイルが存在しません! 実はDocker for mac はmac 上でDocker コンテナが動いているわけではなく、 mac 上で動いているHyperKit VM の中で Docker コンテナが動いているのです。 ということで HyperKit VM へ侵⼊します。 ( 参考: https://uzimihsr.github.io/post/2020-12-15-docker-desktop-for-mac-hyperkit-vm/) docker run -it --rm --privileged --pid=host justincormack/nsenter1 / # ls /var/lib/docker/containers/6a6685a8eaa1eaf6249f86251ae091c7db3360ecf1efbeff6e8a909f7263f084/hostname /var/lib/docker/containers/6a6685a8eaa1eaf6249f86251ae091c7db3360ecf1efbeff6e8a909f7263f084/hostname / # ありました。こんなことになってたんですねー。 後はもう追うのが⼤変なのでこっちを参照してください。 https://dev.classmethod.jp/articles/docker-service-discovery/
  6. YOJO のDocker について説明しつつ少しDeepDive 6 Dockerfile のTips WORKDIR にはADD は不要です。WORKDIR はディレクトリがあれば作ってくれます。

    ADD /app WORKDIR /app ↓ WORKDIR /app 最近のDocker は⾮root ユーザーでの実⾏も可能。↓ をみてね。 https://www.slideshare.net/AkihiroSuda/cndt-docker マルチステージビルドを使うと環境をキレイキレイできるしコンテナサイズをめっちゃ⼩さくできます。 バイナリで動くGo とかと相性がいいです。 # ビルド⽤ FROM golang:latest AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . 引⽤元: https://dev.classmethod.jp/articles/docker-service-discovery/
  7. YOJO のDocker について説明しつつ少しDeepDive 7 RUN go build -o main /app/main.go

    # 実際に動かすDocker コンテナ FROM gcr.io/distroless/base-debian10 WORKDIR / COPY --from=builder /app/main . EXPOSE 8080 USER nonroot:nonroot CMD [ "/app/main" ] distroless はGoogle の作ったセキュアなDocker コンテナ。 https://github.com/GoogleContainerTools/distroless nonroot は⾮root ユーザーの指定。 Docker 奥が深いですね! Docker compose Docker compose は複数のDocker コンテナをいい感じに管理するためのツールです。 例えば調剤のdocker-compose.yml を⾒てみましょう。 version: '3.3' services: pharmacy-dx-admin: ports: - 3335:3335 build: context: ./ dockerfile: Dockerfile container_name: pharmacy-dx-admin command: bash -c "yarn install && yarn dev" tty: true stdin_open: true volumes: - ../:/myapp - ~/.ssh/id_ed25519:/root/.ssh/id_ed25519:ro networks: - pharmax-shared-network networks: default: name: pharmax-pharmacy-admin_default pharmax-shared-network: external: true
  8. YOJO のDocker について説明しつつ少しDeepDive 8 注⽬ポイントは - ~/.ssh/id_ed25519:/root/.ssh/id_ed25519:ro 。何をしているかと⾔うとローカルPC のGithub 登録済みのSSH

    キーをDocker コンテナにSync させ、Docker コンテナ内からgit コマンドを叩けるようにしています。 これをすることで、コンテナ内でgit commit したとき、pharmacy-dx-admin に仕込まれたpre-commit(git commit 時に⾃動的に 実⾏されるコマンド) を実現するhusky が、ローカル環境にhusky やyarn 、npm 、node が⼊ってなくても動いてくれます。便 利! 他にも⽅法があります。それがVSCode のRemote Containers 。説明は省きます。 https://qiita.com/d0ne1s/items/d2649801c6f804019db7 また、ネットワークの云々が合ったと思いますが、1 つのDocker compose 内であれば勝⼿に名前解決できます。たとえば linebot-service 。 version: '3' services: db: build: context: .. dockerfile: docker/db/Dockerfile image: yojo-linebot-db container_name: yojo-linebot-db environment: POSTGRES_PASSWORD: password TZ: "Asia/Tokyo" PGDATA: /tmp/postgresql/data volumes: - ./db/initdb:/docker-entrypoint-initdb.d - ../tmp/db:/tmp/postgresql/data ports: - "5432:5432" redis: image: redis:6.2.1-alpine container_name: yojo-linebot-redis command: redis-server --appendonly yes environment: TZ: Asia/Tokyo volumes: - ../tmp/redis:/data linebot-service: &app_base platform: linux/amd64 build: context: .. dockerfile: docker/web/Dockerfile image: yojo-linebot-service container_name: yojo-linebot-service command: bash -c "bundle install && rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'" environment: POSTGRES_HOST: db POSTGRES_PASSWORD: password REDIS_URL: redis://redis:6379 PRYRC: /myapp/.pryrc volumes: - ../:/myapp - ../tmp/cache/docker:/myapp/tmp/cache ports: - "3000:3000" tty: true stdin_open: true depends_on: - db - redis networks: - default - yojo-shared-network webpacker: <<: *app_base container_name: yojo-linebot-service-webpack command: bash -c "bundle install && bundle exec bin/webpack-dev-server"
  9. YOJO のDocker について説明しつつ少しDeepDive 9 environment: WEBPACKER_DEV_SERVER_HOST: 0.0.0.0 ports: - "3035:3035"

    depends_on: - linebot-service sidekiq: <<: *app_base container_name: yojo-linebot-sidekiq command: bash -c "bundle install && bundle exec sidekiq" ports: [] networks: default: name: yojo-service_default yojo-shared-network: external: true depends on を書いてあげることで、ネットワークは違えども名前解決を作成してくれます。 つまり linebot-service というコンテナから、 ping db とかすれば docker-compose.yml に記載されている db コンテナに対 してping が⾶びます。便利! また、↓ の &app_base というのはYAML のテンプレート記述であり、同じ設定内容の場合は << *app_base として定義できま す。(app_base という単語は対応関係にあれば何でも良いです。) linebot-service: &app_base Rails やってる⼈なら、database.yml がこの記述を利⽤しているのですんなり理解できるでしょう。 docker-compose.yml の先頭⾏ version: '3' は利⽤するバージョンです。基本的に新しいほうが良いので2 とか1 とかの場合は 3 に書き直してあげましょう。 実はリファレンスがめっちゃしっかりしてるのでこれを読めばDocker compose マスターになれる!(ただし分量がめっちゃ 多い) https://docs.docker.jp/compose/compose-file/compose-file-v3.html