Dev Containers で始める快適 Zenn 執筆環境
はじめに
GitHub 連携によるバージョン管理や VSCode での記事作成に魅力を感じたため、セットアップしてみました。
普通に設定を進めると、Node.js や Zenn CLI をインストールしたり、VSCode(+拡張機能)の設定を Zenn 仕様にしたり、と手間がかかります。
また、可能であればローカル環境はクリーンに保ちたいです。
そこで、Dev Containers を用いて Zenn 記事作成用環境を構築してみました。
主なメリットは以下の通りです。
- アプリの依存関係をコンテナ内に隔離し、ローカル環境をクリーンに保てる
- VSCode の設定や Markdown 関連の拡張機能を Zenn 執筆専用の環境として分離できる
- 環境構築手順をコード (Dockerfile、devcontainer.json 等) で管理できる
- 異なるマシンでも同一の執筆環境を再現できる
概要
本記事では以下の内容について順に解説します。
- VSCode の拡張機能「Dev Containers」を利用した環境構築手順
- 実際の使用方法と便利な機能の紹介
- 各種設定や拡張機能の選定に関する話
環境構築
GitHub にて環境構築用のテンプレートを公開しています。
設定ファイルの作成が面倒な方はこちらをご利用ください。
zenn_contents/
├── .git/
├── .devcontainer/
│ ├── devcontainer.json
│ ├── docker-compose.yml
│ └── Dockerfile
├── articles/
│ └── article_name.md
└── images/
└── article_name/
└── image.webp
前提環境
Docker、Git、VSCode Dev Containers は導入済みとします。
インストール方法は各所で説明がされていますので割愛します。
紹介するコマンドは Windows 11 をベースにしています。適宜、別 OS の方は読み替えてください。
Zenn と GitHub の連携
以下の公式解説記事を参考に、リポジトリの作成と連携を実施します。
Dev Containers 設定ファイル作成
ローカルリポジトリ(筆者例:zenn_contents)直下に .devcontainer フォルダを作成します。
以下を参考に、.devcontainer フォルダ内に Dev Containers 用の設定ファイルを作成します。
zenn_contents/
├── .git/
└── .devcontainer/
├── devcontainer.json
├── docker-compose.yml
└── Dockerfile
devcontainer.json
どの docker-compose.yml を使用するかを指定します。
VSCode で使用する拡張機能や設定を指定します。
{
"name": "zenn_contents",
"dockerComposeFile": "docker-compose.yml",
"service": "zenn_contents",
//VScode接続時に開くフォルダを指定
"workspaceFolder": "/work/zenn_contents",
//VScodeの環境を指定
"customizations": {
"vscode": {
//インストールする拡張機能を指定
"extensions": [
"GitHub.copilot",
"GitHub.copilot-chat",
"negokaz.zenn-editor",
"nodamushi.udon"
],
//VScodeの設定を記載
"settings": {
//udon拡張の設定
//ariclesディレクトリにある.mdファイルに画像を貼り付けた際
//workspace/image/aritcle_name/に画像を保存
//画像のリンクは相対リンクではなく、image/...で作成される(zenn 仕様対応)
"udon.baseDirectories": [
["articles/*.md", "${workspaceFolder}/images/$fileBasenameNoExtension"]
],
"udon.rule": [
["articles/*.md", ""],
["*.md", ""],
["*", "${relImage:${workspaceFolder}}"]
]
}
}
}
}
docker-compose.yml
ここと Dockerfile は通常の Docker と同じ書き方で記述します。
docker-compose でコンテナとローカル間のフォルダ共有を設定していますが、devcontainer.json でも同様の設定ができます。
個人的な好みで、Docker 側で設定できる箇所は Docker に任せ、docker-compose.yml には VSCode 関連の設定のみを記載する方針を採用しています。
services:
zenn_contents:
build:
dockerfile: Dockerfile
tty: true
# zenn用のフォルダ全てをマウント
volumes:
- ../:/work/zenn_contents/
Dockerfile
# 軽量なalpineイメージを選択
FROM node:22-alpine3.20
ENV NODE_PATH /opt/node_modules
# gitをコンテナ内で使用する際、ssh接続が必要なため、openssh-clientをインストール
RUN apk update && \
apk add --no-cache git bash openssh-client
# zenn-cliのインストール
WORKDIR /work
RUN npm init --yes && \
npm install -g zenn-cli@latest
# 実際に記事を管理するフォルダを作成
# コンテナとホスト間で共有するフォルダ
WORKDIR /work/zenn_contents
SSH の設定
Zenn 記事の作成から公開まで、すべてコンテナ内で実施できると便利です。
しかし、GitHub と SSH 接続で通信するには、別途設定が必要です。
現状では、コンテナ内で git push
を実行すると、秘密鍵が存在しないためエラーとなります。
Dev Containers では、ローカルで実行中の ssh-agent が存在する場合、SSH 認証情報をコンテナ内で使用する機能が提供されており、これを利用します。
Windows 起動時に ssh-agent が自動的に起動するように設定します。
# SSHエージェントサービスを自動起動に設定
Set-Service ssh-agent -StartupType Automatic
# SSHエージェントサービスを開始
Start-Service ssh-agent
もし、ssh-agent に GitHub 用の秘密鍵が登録されていない場合は、以下の手順で登録してください。
# 登録されている秘密鍵を確認
ssh-add -l
# .ssh 直下にある秘密鍵を登録(例: ~/.ssh/id_ed25519)
ssh-add
# 特定の秘密鍵を指定して登録する場合
ssh-add ~/.ssh/GitHub/id_ed25519
使い方
初めて起動する際の操作
コンテナの起動
VSCode で記事執筆用のディレクトリを開きます。
次に、コマンドパレットから Rebuild Container Without Cache and Reopen in Container
を選択します。
自動的に Docker コンテナのビルドが開始されます。
右下の「開発コンテナへ接続中」表記が消えるまで、数秒待ちます。
拡張機能の再読み込み
初回のみ、拡張機能の読み込みが正常に行われないことがあります。
コンテナを出入りすることで解消されます。
コンテナから出るには、以下のいずれかを実施してください。
- 「ファイル」>「最近使用した項目を開く」から記事執筆用のディレクトリを選択する
- 画面左下の青い
><
マークをクリックし、コマンドパレットからリモート接続を終了する
を選択する
作成済みのコンテナに入る方法は以下の通りです。
- 「ファイル」>「最近使用した項目を開く」から、
[Dev Container]
と表示されているディレクトリを選択する - コマンドパレットにて
Reopen in Container
を選択する
Zenn CLI の初期化
この状態では、ブラウザでのプレビュー機能が動作しないため、コンテナ内で以下のコマンドを実行してください。
npx zenn init
これにて執筆環境の構築は完了となります。
細かい操作方法について
画像の貼り付け
Ctrl + Alt + V
で画像を貼り付けできます。
- 画像ファイルのコピペ
- スクリーンショットのペースト
どちらも対応しています。
md.ファイル内でのリンク形式は、自動的にZenn 仕様 
となります。
画像は下記フォルダに保存されます。
zenn_contents/
├── articles/
│ └── article_name.md
└── images/
└── article_name/
└── image.webp
画像の貼り付けは udon 拡張機能によるものです。
詳細は下記をご確認ください。
エクスプローラー、プレビュー機能
通常、Zenn 記事の .md ファイル名はタイトルと一致していません。
しかし、エクスプローラーで ZENN CONTENTS を展開すると、記事ファイルがタイトルで表示され、操作しやすくなります。
通常のプレビューボタンの横に Z 印が付いたボタンが追加されています。
(md.ファイルのウィンドウ右上、左から2番目のボタン)
こちらを押すと、Web ブラウザでのプレビューと同様に zenn 仕様でのプレビューが VSCode 内で表示されます。
これらの機能は Zenn editor 拡張機能によるものです。
詳細は以下をご確認ください。
設定ファイルを書き換えた場合
devcontainer.json
や Dockerfile
を変更した場合は、コマンドパレットにて Rebuild Container Without Cache and Reopen in Container
を実行してください。
各種設定や拡張機能の選定
この章では、Dev Containers の設定を自分好みカスタマイズしたい方に向けて情報を残したいと思います。
VSCode の設定や拡張機能の選定、環境構築中に直面した問題とその解決策、といった内容を雑に述べていきます。
VSCode の設定
基本的には、普段使用しているローカル設定がそのまま引き継がれるため、変更したい部分のみを devcontainer.json
に記載します。
現在の設定情報は、Ctrl + ,
で設定を開き、右上のファイルボタンをクリックすると、JSON 形式で確認できます。
これらの内容を適宜 devcontainer.json
の settings
にコピペすることで、編集が容易になります。
udon 拡張の設定のように、Zenn に特化した設定はローカルに依存せず、devcontainer.json
に隔離して管理する方が、余計なトラブルの発生を防ぐ上で有効です。
VSCode の拡張機能
私の拡張機能の設定は、比較的シンプルな構成となっています。
{
"customizations": {
"vscode": {
"extensions": [
"GitHub.copilot",
"GitHub.copilot-chat",
"negokaz.zenn-editor",
"nodamushi.udon"
]
}
}
}
以下の参考記事をもとに、リンターやフォーマッターなどの拡張機能を追加するのもおすすめです。
このような拡張機能やその設定も、devcontainer.json
で一元管理できるため、他の開発環境に左右されずに Zenn に特化したカスタマイズが可能です。
この点が、私が Dev Containers を特に気に入っている理由です。
環境構築で大変だった事
拡張機能が Active にならない!
Rebuild Container Without Cache and Reopen in Container
を実行してコンテナを再構築した際、zenn editor が Active 状態になりませんでした。
Reopen in Container
を実行すると Active 状態にはなりますが、根本的な解決には至っていないため、しこりが残っています。
画像貼り付けと Zenn 仕様のリンク
初期案では、画像の貼り付けを VSCode の標準機能で行うための設定を書いていました。
{
"customizations": {
"vscode": {
"settings": {
// 旧設定
"markdown.copyFiles.destination": {
"/articles/**/*": "images/articles/${documentBaseName}/"
}
}
}
}
}
しかし、この設定だと .md にに画像を貼り付けた際、
のようにリンクが作成されます。
そのため、Zenn 仕様の 
に手動で書き換える手間が発生してしまいます。
また、paste image などの拡張機能も存在しますが、WSL 環境では動作しないため、Windows ユーザーには適していません。
なお、無理やり動作させる方法もありますが、設定が複雑になりがちです。
そこで見つけたのが udon 拡張でした。
控えめに言って神拡張です。
設定の手間を大幅に削減できました。
おわりに
本記事をきっかけに、ブラウザでの執筆から VSCode での執筆に切り替えました。
やはり、使い慣れた VSCode の方が作業効率も良く、快適に執筆できます。
今後、拡張機能を追加して「こうだったらいいな」というアイデアを実現しながら、少しずつ自分好みにカスタマイズしていく予定です。
Discussion