~fvknk/bk

技術関連の備忘録

docker init を試してみる

はじめに

Dockerfilecompose.yamlを自動生成してくれるdocker initコマンドが使えるようになったようなので、早速試しに使ってみました。

www.docker.com

実行環境

  • macOS:Sonoma 14.3
  • Docker:4.27.1

実際にやってみる

まずは基本的なケースを試してみる

適当な作業用ディレクトリを作成し、早速docker initコマンドを実行したところ、以下のようなメニューが表示されました。

どうやら、.dockerignoreDockerfilecompose.yamlREADME.Docker.mdを自動生成してくれるようです。

$ docker init

Welcome to the Docker Init CLI!

This utility will walk you through creating the following files with sensible defaults for your project:
  - .dockerignore
  - Dockerfile
  - compose.yaml
  - README.Docker.md

Let's get started!

? What application platform does your project use?  [Use arrows to move, type to filter]
  Go - suitable for a Go server application
  Python - suitable for a Python server application
  Node - suitable for a Node server application
  Rust - suitable for a Rust server application
  ASP.NET Core - suitable for an ASP.NET Core application
  PHP with Apache - suitable for a PHP web application
  Java - suitable for a Java application that uses Maven and packages as an uber jar
> Other - general purpose starting point for containerizing your application
  Don't see something you need? Let us know!
  Quit

今回はひとまず Otherを選択して、汎用的なコンテナを作成してもらいました。

$ docker init

Welcome to the Docker Init CLI!

This utility will walk you through creating the following files with sensible defaults for your project:
  - .dockerignore
  - Dockerfile
  - compose.yaml
  - README.Docker.md

Let's get started!

? What application platform does your project use? Other

CREATED: .dockerignore
CREATED: Dockerfile
CREATED: compose.yaml
CREATED: README.Docker.md

✔ Your Docker files are ready!

Take a moment to review them and tailor them to your application.

When you're ready, start your application by running: docker compose up --build

Consult README.Docker.md for more information about using the generated files.

プロジェクトを選択したところ、すぐに処理が完了して、実行コマンドが表示されました。

念の為ls -aコマンドを実行したところ、本当にファイルが生えていました。

$ ls -a 
.                .dockerignore    README.Docker.md
..               Dockerfile       compose.yaml

compose.yamlの中身は以下のようになっているようです。

コメントアウトを外せばDBもすぐに使用できるようになっているようでありがたいです。

# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Docker compose reference guide at
# https://docs.docker.com/go/compose-spec-reference/

# Here the instructions define your application as a service called "app".
# This service is built from the Dockerfile in the current directory.
# You can add other services your application may depend on here, such as a
# database or a cache. For examples, see the Awesome Compose repository:
# https://github.com/docker/awesome-compose
services:
  app:
    build:
      context: .
      target: final
    # If your application exposes a port, uncomment the following lines and change
    # the port numbers as needed. The first number is the host port and the second
    # is the port inside the container.
    # ports:
    #   - 8080:8080

    # The commented out section below is an example of how to define a PostgreSQL
    # database that your application can use. `depends_on` tells Docker Compose to
    # start the database before your application. The `db-data` volume persists the
    # database data between container restarts. The `db-password` secret is used
    # to set the database password. You must create `db/password.txt` and add
    # a password of your choosing to it before running `docker compose up`.
    #     depends_on:
    #       db:
    #         condition: service_healthy
    #   db:
    #     image: postgres
    #     restart: always
    #     user: postgres
    #     secrets:
    #       - db-password
    #     volumes:
    #       - db-data:/var/lib/postgresql/data
    #     environment:
    #       - POSTGRES_DB=example
    #       - POSTGRES_PASSWORD_FILE=/run/secrets/db-password
    #     expose:
    #       - 5432
    #     healthcheck:
    #       test: [ "CMD", "pg_isready" ]
    #       interval: 10s
    #       timeout: 5s
    #       retries: 5
    # volumes:
    #   db-data:
    # secrets:
    #   db-password:
    #     file: db/password.txt

Dockerfileは以下のようになっているようです。

「Hello world from appuser! In order to get your application running in a container, take a look at the comments in the Dockerfile to get started.」と表示されれば成功していると見て良さそうです。

# syntax=docker/dockerfile:1

# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Dockerfile reference guide at
# https://docs.docker.com/go/dockerfile-reference/

# Want to help us make this template better? Share your feedback here: https://forms.gle/ybq9Krt8jtBL3iCk7

################################################################################
# Pick a base image to serve as the foundation for the other build stages in
# this file.
#
# For illustrative purposes, the following FROM command
# is using the alpine image (see https://hub.docker.com/_/alpine).
# By specifying the "latest" tag, it will also use whatever happens to be the
# most recent version of that image when you build your Dockerfile.
# If reproducability is important, consider using a versioned tag
# (e.g., alpine:3.17.2) or SHA (e.g., alpine@sha256:c41ab5c992deb4fe7e5da09f67a8804a46bd0592bfdf0b1847dde0e0889d2bff).
FROM alpine:latest as base

################################################################################
# Create a stage for building/compiling the application.
#
# The following commands will leverage the "base" stage above to generate
# a "hello world" script and make it executable, but for a real application, you
# would issue a RUN command for your application's build process to generate the
# executable. For language-specific examples, take a look at the Dockerfiles in
# the Awesome Compose repository: https://github.com/docker/awesome-compose
FROM base as build
RUN echo -e '#!/bin/sh\n\
echo Hello world from $(whoami)! In order to get your application running in a container, take a look at the comments in the Dockerfile to get started.'\
> /bin/hello.sh
RUN chmod +x /bin/hello.sh

################################################################################
# Create a final stage for running your application.
#
# The following commands copy the output from the "build" stage above and tell
# the container runtime to execute it when the image is run. Ideally this stage
# contains the minimal runtime dependencies for the application as to produce
# the smallest image possible. This often means using a different and smaller
# image than the one used for building the application, but for illustrative
# purposes the "base" image is used here.
FROM base AS final

# Create a non-privileged user that the app will run under.
# See https://docs.docker.com/go/dockerfile-user-best-practices/
ARG UID=10001
RUN adduser \
    --disabled-password \
    --gecos "" \
    --home "/nonexistent" \
    --shell "/sbin/nologin" \
    --no-create-home \
    --uid "${UID}" \
    appuser
USER appuser

# Copy the executable from the "build" stage.
COPY --from=build /bin/hello.sh /bin/

# What the container should run when it is started.
ENTRYPOINT [ "/bin/hello.sh" ]

docker compose up --buildを実行します。

$ docker compose up --build
[+] Building 11.3s (11/11) FINISHED                                                                                                                                                                                      docker:desktop-linux
 => [app internal] load build definition from Dockerfile                                                                                                                                                                                 0.1s
 => => transferring dockerfile: 2.88kB                                                                                                                                                                                                   0.0s
 => [app] resolve image config for docker.io/docker/dockerfile:1                                                                                                                                                                         3.6s
 => [app] docker-image://docker.io/docker/dockerfile:1@sha256:ac85f380a63b13dfcefa89046420e1781752bab202122f8f50032edf31be0021                                                                                                           2.0s
 => => resolve docker.io/docker/dockerfile:1@sha256:ac85f380a63b13dfcefa89046420e1781752bab202122f8f50032edf31be0021                                                                                                                     0.0s
 => => sha256:9d9c93f4b00be908ab694a4df732570bced3b8a96b7515d70ff93402179ad232 11.80MB / 11.80MB                                                                                                                                         1.3s
 => => sha256:ac85f380a63b13dfcefa89046420e1781752bab202122f8f50032edf31be0021 8.40kB / 8.40kB                                                                                                                                           0.0s
 => => sha256:657fcc512c7369f4cb3d94ea329150f8daf626bc838b1a1e81f1834c73ecc77e 482B / 482B                                                                                                                                               0.0s
 => => sha256:a17ee7fff8f5e97b974f5b48f51647d2cf28d543f2aa6c11aaa0ea431b44bb89 1.27kB / 1.27kB                                                                                                                                           0.0s
 => => extracting sha256:9d9c93f4b00be908ab694a4df732570bced3b8a96b7515d70ff93402179ad232                                                                                                                                                0.6s
 => [app internal] load metadata for docker.io/library/alpine:latest                                                                                                                                                                     2.3s
 => [app internal] load .dockerignore                                                                                                                                                                                                    0.0s
 => => transferring context: 667B                                                                                                                                                                                                        0.0s
 => [app base 1/1] FROM docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b                                                                                                          1.2s
 => => resolve docker.io/library/alpine:latest@sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b                                                                                                                   0.0s
 => => sha256:c5b1261d6d3e43071626931fc004f70149baeba2c8ec672bd4f27761f8e1ad6b 1.64kB / 1.64kB                                                                                                                                           0.0s
 => => sha256:6457d53fb065d6f250e1504b9bc42d5b6c65941d57532c072d929dd0628977d0 528B / 528B                                                                                                                                               0.0s
 => => sha256:05455a08881ea9cf0e752bc48e61bbd71a34c029bb13df01e40e3e70e0d007bd 1.47kB / 1.47kB                                                                                                                                           0.0s
 => => sha256:4abcf20661432fb2d719aaf90656f55c287f8ca915dc1c92ec14ff61e67fbaf8 3.41MB / 3.41MB                                                                                                                                           0.6s
 => => extracting sha256:4abcf20661432fb2d719aaf90656f55c287f8ca915dc1c92ec14ff61e67fbaf8                                                                                                                                                0.4s
 => [app build 1/2] RUN echo -e '#!/bin/sh\necho Hello world from $(whoami)! In order to get your application running in a container, take a look at the comments in the Dockerfile to get started.'> /bin/hello.sh                      0.7s
 => [app final 1/2] RUN adduser     --disabled-password     --gecos ""     --home "/nonexistent"     --shell "/sbin/nologin"     --no-create-home     --uid "10001"     appuser                                                          0.7s
 => [app build 2/2] RUN chmod +x /bin/hello.sh                                                                                                                                                                                           0.6s
 => [app final 2/2] COPY --from=build /bin/hello.sh /bin/                                                                                                                                                                                0.1s
 => [app] exporting to image                                                                                                                                                                                                             0.1s
 => => exporting layers                                                                                                                                                                                                                  0.1s
 => => writing image sha256:53c892d7cb61f29514101b9605d5d820ad7384c5aa93afa7d724dc8969702798                                                                                                                                             0.0s
 => => naming to docker.io/library/docker-init-app                                                                                                                                                                                       0.0s
[+] Running 2/2
 ✔ Network docker-init_default  Created                                                                                                                                                                                                  0.1s 
 ✔ Container docker-init-app-1  Created                                                                                                                                                                                                  0.2s 
Attaching to app-1
app-1  | Hello world from appuser! In order to get your application running in a container, take a look at the comments in the Dockerfile to get started.
app-1 exited with code 0

事前の想定通りのメッセージが表示されました。

事前に準備されたプラットフォームを選択する

再度docker initを実行して、Nodeを選択してみました。

最終的には以下のガイドに沿って行うのがスマートそうです。 (無視して先にdocker initを実行したところ、クローンしたサンプルファイルを移動するか、compose.yamlを編集するかが必要になりました……)

docs.docker.com

ひとまずサンプルのリポジトリをクローンしてきて、ディレクトリを移動後、docker initを実行しました。 Nodeの場合、バージョン、パッケージマネージャー、アプリケーションの実行コマンド、ポート番号が指定できるようです。また、アプリケーションの実行コマンドは、すでにファイルが存在する場合はある程度推測してくれるようです。が、今回はsrcディレクトリ配下にファイルが入っており、デフォルト値とは異なっていたため明示的に指定しています。

$ git clone https://github.com/docker/docker-nodejs-sample            
Cloning into 'docker-nodejs-sample'...
remote: Enumerating objects: 61, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 61 (delta 2), reused 2 (delta 2), pack-reused 55
Receiving objects: 100% (61/61), 1.71 MiB | 5.65 MiB/s, done.
Resolving deltas: 100% (6/6), done.
$ cd docker-nodejs-sample/
$ docker init              

Welcome to the Docker Init CLI!

This utility will walk you through creating the following files with sensible defaults for your project:
  - .dockerignore
  - Dockerfile
  - compose.yaml
  - README.Docker.md

Let's get started!

? Do you want to overwrite them? Yes
? What application platform does your project use? Node
? What version of Node do you want to use? 19.4.0
? Which package manager do you want to use? npm
? What command do you want to use to start the app? node src/index.js
? What port does your server listen on? 3000

CREATED: .dockerignore
CREATED: Dockerfile
CREATED: compose.yaml
CREATED: README.Docker.md

✔ Your Docker files are ready!

Take a moment to review them and tailor them to your application.

When you're ready, start your application by running: docker compose up --build

Your application will be available at http://localhost:3000

先ほどと同様、実行コマンドが表示されているのでdocker compose up —buildを実行したところ、正常に起動しました。

$ docker compose up --build
[+] Building 2.7s (11/11) FINISHED                                                            docker:desktop-linux
 => [server internal] load build definition from Dockerfile                                                   0.0s
 => => transferring dockerfile: 1.21kB                                                                        0.0s
 => [server] resolve image config for docker.io/docker/dockerfile:1                                           1.3s
 => CACHED [server] docker-image://docker.io/docker/dockerfile:1@sha256:ac85f380a63b13dfcefa89046420e1781752  0.0s
 => [server internal] load metadata for docker.io/library/node:19.4.0-alpine                                  0.9s
 => [server internal] load .dockerignore                                                                      0.0s
 => => transferring context: 659B                                                                             0.0s
 => [server stage-0 1/4] FROM docker.io/library/node:19.4.0-alpine@sha256:ab3603cb7934b21f1ffb522b1a1d538809  0.0s
 => [server internal] load build context                                                                      0.0s
 => => transferring context: 2.51kB                                                                           0.0s
 => CACHED [server stage-0 2/4] WORKDIR /usr/src/app                                                          0.0s
 => CACHED [server stage-0 3/4] RUN --mount=type=bind,source=package.json,target=package.json     --mount=ty  0.0s
 => CACHED [server stage-0 4/4] COPY . .                                                                      0.0s
 => [server] exporting to image                                                                               0.0s
 => => exporting layers                                                                                       0.0s
 => => writing image sha256:de5217186e7035038bec6263f52c28f67d67a0d608e25bc34cf18556093557cc                  0.0s
 => => naming to docker.io/library/docker-nodejs-sample-server                                                0.0s
[+] Running 2/2
 ✔ Network docker-nodejs-sample_default     Created                                                           0.1s 
 ✔ Container docker-nodejs-sample-server-1  Created                                                           0.1s 
Attaching to server-1
server-1  | Using sqlite database at /tmp/todo.db
server-1  | Listening on port 3000

ブラウザでhttp://localhost:3000へアクセスしたところ、以下のようなサイトが表示されていました。

まとめ

今回のような自動生成のコマンドができることで、いちいちDocker関連のファイルの書き方を調べることなく、試しにDockerで環境を作って手を動かしてみるといった作業がしやすくなって、非常にありがたいと感じました。 上記の使い方の場合、docker initでプラットフォームを選択したらよしなにサンプルのファイルを作成してくれるところまでやってくれるとありがたいのですが、そこまでをdocker initのコマンドにさせるのは責任過多な気がしているので、今回のNodeの例ようにファイル群は別途用意して、あくまでDocker関連のファイル群の生成に使うのがベターかなと思いました。