Closed6

Docker で Zenn の執筆環境を作ってみる

ピン留めされたアイテム
nagakutanagakuta

なんで?

Docker for Mac が Apple Silicon に対応した。
ローカルで Markdown ゴリゴリ書いてもいいんだけど、Docker のことを学ぶついでに。

環境

  • Macbook Air (M1, 2020)
  • Docker for Mac: 3.3.1
nagakutanagakuta

Docker for Mac のインストール

まあ、Homebrew-cask で入れるほうが丸かろう。

Homebrew のインストール

$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
...
$ export PATH=/opt/homebrew/bin:$PATH
$ brew --help
Example usage:
  brew search TEXT|/REGEX/
  brew info [FORMULA|CASK...]
  brew install FORMULA|CASK...
  brew update
  brew upgrade [FORMULA|CASK...]
  brew uninstall FORMULA|CASK...
  brew list [FORMULA|CASK...]

Troubleshooting:
  brew config
  brew doctor
  brew install --verbose --debug FORMULA|CASK

Contributing:
  brew create URL [--no-fetch]
  brew edit [FORMULA|CASK...]

Further help:
  brew commands
  brew help [COMMAND]
  man brew
  https://docs.brew.sh

Docker for Mac のインストール

外部からインスコする App は $HOME/Applications に入れておきたい人なので。

$ brew install --cask --appdir=$HOME/Applications docker

Docker 起動

インスコした Docker for Mac を起動、「コマンド入れたいから許可してやー」のダイアログが表示されるのでええんやでする。
暫し待つと Docker 周りのコマンドがインスコされる。

$ which docker
/usr/local/bin/docker
$ docker version
Client: Docker Engine - Community
 Cloud integration: 1.0.12
 Version:           20.10.5
 API version:       1.41
 Go version:        go1.13.15
 Git commit:        55c4c88
 Built:             Tue Mar  2 20:13:00 2021
 OS/Arch:           darwin/amd64 (rosetta)
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.5
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       363e9a8
  Built:            Tue Mar  2 20:16:48 2021
  OS/Arch:          linux/arm64
  Experimental:     false
 containerd:
  Version:          1.4.4
  GitCommit:        05f951a3781f4f2c1911b05e61c160e9c30eaa8e
 runc:
  Version:          1.0.0-rc93
  GitCommit:        12644e614e25b05da6fd08a38ffa0cfe1903fdec
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

うん、大丈夫そう。

nagakutanagakuta

Container を作る

というわけで、初めての Container 作り開始。
右も左も分からないので素直にググってみる。

どうやら、Dockerfile とやらを作らないといけないらしい。

Dockerfile を作る

Visual Studio Code Lover なので VSCodeDockerRemote - Containers の拡張を突っ込んで Dockerfile を作ってみる。

Zenn CLI は nodejs を利用する形らしい。nodejs を利用できる Container image を使うことにした。

この記事 によると、Alpine(?)よりも Distroless(?)のほうが良いらしい。

が、どうやら Distroless では /bin/bash がインストールされていないらしく、Remote - Containers では起動することができなかった。

現時点で aarch64(arm64)に対応しているのが node:buster とのこと (参考) なので、それをベースの image に選択した。

.devcontainer/zenn/Dockerfile
# Base image
FROM node:15.14.0-buster-slim

# Maintainer
LABEL maintainer="nagakuta <xxx@example.com>"

Remote - Containers で動いたことを確認、よしよし。

nagakutanagakuta

Zenn CLI を入れる

本題。Zenn CLI を入れる。
先程の Dockerfile で build 時に Zenn CLI をインスコするようにする。

…と、ここで問題発生。どうやら何も考えずに npm install を Container 上で行うとハチャメチャに遅いらしい。
とのことで解決策をググる。ヒットしたのは「npm install 前に registry を http://registry.npmjs.org/ に指定しておく」だった(参考)。

.devcontainer/zenn/Dockerfile
# Base image
FROM node:15.14.0-buster-slim

# Maintainer
LABEL maintainer="nagakuta <xxx@example.com>"

+# Workdir
+WORKDIR /workspace

+# Copy files into container
+COPY articles/ books/ README.md .

+# Install Zenn CLI
+ENV NODE_ENV=production
+RUN npm config set registry http://registry.npmjs.org/
+RUN npm install -g npm --verbose
+RUN npm install --production zenn-cli --verbose
.devcontainer/docker-compose.yml
version: '3.8'
services:
    build:
      context: .
      dockerfile: zenn/Dockerfile
    volumes:
      - ..:/workspace:cached
    ports: 
      - 3000:3000
    command: /bin/sh -c "while sleep 1000; do :; done"
nagakutanagakuta

docker build 時に npx zenn init してみたが、なぜか RUN npx zenn init した結果が Container のどこにも見当たらない。
ログ的には実行しているっぽいので、どこかしらのフォルダには npx zenn init した結果が展開されているはずなのだが…

まあ、Container 内で npx zenn init を打てばいいっちゃいいのでそこまで手間ではないし、基本的に Mac の local にリポジトリを clone してから build するから問題ないんだけど、モヤッとする。

nagakutanagakuta

Docker ときちんと向き合ってみる

ここで、Dockerfiledocker-compose.yml をきちんと見つめ直してみる(ほぼほぼコピペだったので)。

Dockerfile

  • COPY はファイルが増えたときに記述量が増えていくだろう。
    → 管理が面倒になるのが目に見えているので別の方法を考える。
  • なんと、RUN 命令を実行するたびにイメージレイヤ(?)が生成されて少し容量が増えるらしい。
    → RUN はまとめるようにする。

これらをまとめると、

.devcontainer/zenn/Dockerfile
# Base image
FROM node:15.14.0-buster-slim

# Maintainer
LABEL maintainer="nagakuta <xxx@example.com>"

# Workdir
WORKDIR /workspace

-# Copy files into container
-COPY articles/ books/ README.md .

# Install Zenn CLI
ENV NODE_ENV=production
-RUN npm config set registry http://registry.npmjs.org/
-RUN npm install -g npm --verbose
-RUN npm install --production zenn-cli --verbose
+RUN npm config set registry http://registry.npmjs.org && \
+    npm install --production zenn-cli --verbose && \
+    rm /workspace/package*.json

docker-compose.yml

  • volumes でディレクトリ全体を永続化している。
    → volumes は Container 内に永続化したいファイルのみをマウント(?)するらしい。

ってことで、修正。

.devcontainer/docker-compose.yml
version: '3.8'
services:
    build:
      context: .
      dockerfile: zenn/Dockerfile
    volumes:
-     - ..:/workspace:cached
+     - ../articles:/workspace/articles:cached
+     - ../books:/workspace/books:cached
+     - ../README.md:/workspace/README.md:cached
    ports: 
      - 3000:3000
    command: /bin/sh -c "while sleep 1000; do :; done"

これで自分が達成したかった「必要なファイルのみが Container 内に送られている」ができた。嬉しい。

このスクラップは2021/04/22にクローズされました