-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile
More file actions
256 lines (228 loc) · 13 KB
/
Copy pathDockerfile
File metadata and controls
256 lines (228 loc) · 13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
FROM ubuntu:24.04
ARG DEBIAN_FRONTEND=noninteractive
# =============================================================================
# 1. System packages + git PPA (git >= 2.48 for worktree.useRelativePaths)
# =============================================================================
RUN apt-get update && apt-get install -y --no-install-recommends \
software-properties-common \
&& add-apt-repository -y ppa:git-core/ppa \
&& apt-get update && apt-get install -y --no-install-recommends \
git \
zsh \
tmux \
ripgrep \
jq \
build-essential \
curl \
wget \
unzip \
zip \
ca-certificates \
gnupg \
sudo \
vim \
locales \
xclip \
openssh-client \
openssh-server \
rsync \
postgresql-client \
direnv \
libgl1 \
libglib2.0-0t64 \
&& locale-gen en_US.UTF-8 \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
ENV LANG=en_US.UTF-8
ENV LANGUAGE=en_US:en
ENV LC_ALL=en_US.UTF-8
# =============================================================================
# 2. GitHub CLI (official apt repository)
# =============================================================================
RUN curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
| dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
&& chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
| tee /etc/apt/sources.list.d/github-cli.list > /dev/null \
&& apt-get update && apt-get install -y --no-install-recommends gh \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# =============================================================================
# 3. Docker CLI (official apt, docker-ce-cli only)
# =============================================================================
RUN install -m 0755 -d /etc/apt/keyrings \
&& curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc \
&& chmod a+r /etc/apt/keyrings/docker.asc \
&& echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
| tee /etc/apt/sources.list.d/docker.list > /dev/null \
&& apt-get update && apt-get install -y --no-install-recommends \
docker-ce-cli \
docker-buildx-plugin \
docker-compose-plugin \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# =============================================================================
# 4. User creation (devuser, UID 1000, zsh, passwordless sudo)
# =============================================================================
RUN userdel -r ubuntu 2>/dev/null; groupdel ubuntu 2>/dev/null; \
groupadd -g 1000 devuser \
&& useradd -m -u 1000 -g 1000 -s /bin/zsh devuser \
&& echo "devuser ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/devuser \
&& chmod 0440 /etc/sudoers.d/devuser \
# useradd creates a "!"-locked account (no password). sshd refuses pubkey
# logins to locked accounts unless UsePAM is on; unlock it so SSH works
# regardless of PAM. The account stays passwordless (no password login).
&& usermod -p '*' devuser
# =============================================================================
# 5. Binary tools (ghq, go-task, AWS CLI, Terraform)
# =============================================================================
# ghq
RUN ARCH=$(dpkg --print-architecture) \
&& GHQ_VERSION=$(curl -fsSL https://api.github.com/repos/x-motemen/ghq/releases/latest | jq -r .tag_name | sed 's/^v//') \
&& if [ "$ARCH" = "amd64" ]; then GHQ_ARCH="amd64"; else GHQ_ARCH="arm64"; fi \
&& curl -fsSL "https://github.com/x-motemen/ghq/releases/download/v${GHQ_VERSION}/ghq_linux_${GHQ_ARCH}.zip" -o /tmp/ghq.zip \
&& unzip /tmp/ghq.zip -d /tmp/ghq \
&& mv /tmp/ghq/ghq_linux_${GHQ_ARCH}/ghq /usr/local/bin/ghq \
&& chmod +x /usr/local/bin/ghq \
&& rm -rf /tmp/ghq /tmp/ghq.zip
# lazygit
RUN ARCH=$(dpkg --print-architecture) \
&& if [ "$ARCH" = "amd64" ]; then LG_ARCH="x86_64"; else LG_ARCH="arm64"; fi \
&& LG_VERSION=$(curl -fsSL https://api.github.com/repos/jesseduffield/lazygit/releases/latest | jq -r .tag_name | sed 's/^v//') \
&& curl -fsSL "https://github.com/jesseduffield/lazygit/releases/download/v${LG_VERSION}/lazygit_${LG_VERSION}_linux_${LG_ARCH}.tar.gz" \
| tar -xz -C /usr/local/bin lazygit
# gwq (git worktree manager)
RUN ARCH=$(dpkg --print-architecture) \
&& if [ "$ARCH" = "amd64" ]; then GWQ_ARCH="x86_64"; else GWQ_ARCH="arm64"; fi \
&& GWQ_VERSION=$(curl -fsSL https://api.github.com/repos/d-kuro/gwq/releases/latest | jq -r .tag_name | sed 's/^v//') \
&& curl -fsSL "https://github.com/d-kuro/gwq/releases/download/v${GWQ_VERSION}/gwq_Linux_${GWQ_ARCH}.tar.gz" \
| tar -xz -C /usr/local/bin gwq
# uv (Python package manager)
RUN curl -LsSf https://astral.sh/uv/install.sh | sh && mv /root/.local/bin/uv /usr/local/bin/ && mv /root/.local/bin/uvx /usr/local/bin/
# go-task
RUN sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin
# AWS CLI v2
RUN ARCH=$(dpkg --print-architecture) \
&& if [ "$ARCH" = "amd64" ]; then AWS_ARCH="x86_64"; else AWS_ARCH="aarch64"; fi \
&& curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-${AWS_ARCH}.zip" -o /tmp/awscli.zip \
&& unzip /tmp/awscli.zip -d /tmp \
&& /tmp/aws/install \
&& rm -rf /tmp/aws /tmp/awscli.zip
# Terraform
RUN ARCH=$(dpkg --print-architecture) \
&& TF_VERSION=$(curl -fsSL https://api.github.com/repos/hashicorp/terraform/releases/latest | jq -r .tag_name | sed 's/^v//') \
&& curl -fsSL "https://releases.hashicorp.com/terraform/${TF_VERSION}/terraform_${TF_VERSION}_linux_${ARCH}.zip" -o /tmp/terraform.zip \
&& unzip /tmp/terraform.zip -d /usr/local/bin \
&& chmod +x /usr/local/bin/terraform \
&& rm /tmp/terraform.zip
# Google Cloud CLI (includes bq for BigQuery)
RUN curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg \
| gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" \
| tee /etc/apt/sources.list.d/google-cloud-sdk.list \
&& apt-get update && apt-get install -y --no-install-recommends google-cloud-cli \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# yq (YAML/JSON/XML processor)
RUN ARCH=$(dpkg --print-architecture) \
&& YQ_VERSION=$(curl -fsSL https://api.github.com/repos/mikefarah/yq/releases/latest | jq -r .tag_name | sed 's/^v//') \
&& curl -fsSL "https://github.com/mikefarah/yq/releases/download/v${YQ_VERSION}/yq_linux_${ARCH}" -o /usr/local/bin/yq \
&& chmod +x /usr/local/bin/yq
# fzf (latest, for --zsh support / Ctrl+R history search)
RUN FZF_VERSION=$(curl -fsSL https://api.github.com/repos/junegunn/fzf/releases/latest | jq -r .tag_name | sed 's/^v//') \
&& ARCH=$(dpkg --print-architecture) \
&& curl -fsSL "https://github.com/junegunn/fzf/releases/download/v${FZF_VERSION}/fzf-${FZF_VERSION}-linux_${ARCH}.tar.gz" \
| tar -xz -C /usr/local/bin
# =============================================================================
# 5b. draw.io CLI (ヘッドレスで .drawio -> png/pdf/svg を書き出す)
# =============================================================================
# drawio-desktop は Electron アプリなので、ヘッドレスで動かすには X サーバ
# (xvfb) とサンドボックス無効化が要る。
#
# libasound2t64 は明示的に入れる。deb の依存では Recommends 扱いで、
# --no-install-recommends だと落ちてしまい、起動時に
# 「libasound.so.2: cannot open shared object file」で失敗する。
#
# fonts-noto-cjk はコンテナに日本語フォントが無いため必須。入れないと
# 日本語のラベルが全部 □(豆腐)になった PNG が出来上がる。
RUN DRAWIO_VERSION=$(curl -fsSL https://api.github.com/repos/jgraph/drawio-desktop/releases/latest | jq -r .tag_name | sed 's/^v//') \
&& ARCH=$(dpkg --print-architecture) \
&& curl -fsSL "https://github.com/jgraph/drawio-desktop/releases/download/v${DRAWIO_VERSION}/drawio-${ARCH}-${DRAWIO_VERSION}.deb" \
-o /tmp/drawio.deb \
&& apt-get update \
&& apt-get install -y --no-install-recommends /tmp/drawio.deb xvfb libasound2t64 fonts-noto-cjk \
&& rm /tmp/drawio.deb \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# drawio を素で呼ぶと DISPLAY 無し・サンドボックス有効で落ちるので、
# xvfb と --no-sandbox を噛ませたラッパを標準の入口にする。
# drawio-export -x -e -f png -o out.drawio.png in.drawio
COPY scripts/drawio-export /usr/local/bin/drawio-export
RUN chmod +x /usr/local/bin/drawio-export
# =============================================================================
# 6. Dotfiles to /etc/skel/ (home is overwritten by volume)
# =============================================================================
COPY config/ssh_config /etc/ssh/ssh_config.d/99-devcontainer.conf
# sshd config for Zed remote development (port 2223). The privilege-separation
# dir is needed for sshd to start.
COPY config/sshd_config /etc/ssh/sshd_config.d/zed.conf
RUN mkdir -p /run/sshd
COPY config/.zshenv /etc/skel/.zshenv
COPY config/.zshrc /etc/skel/.zshrc
COPY config/.gitconfig /etc/skel/.gitconfig
COPY config/.tmux.conf /etc/skel/.tmux.conf
COPY config/.gitmux.conf /etc/skel/.gitmux.conf
# ステータスバーから gitmux を呼ぶラッパー(.tmux.conf が参照する)
RUN mkdir -p /etc/skel/.tmux
COPY config/gitmux-cached.sh /etc/skel/.tmux/gitmux-cached.sh
RUN chmod 755 /etc/skel/.tmux/gitmux-cached.sh
RUN mkdir -p /etc/skel/.config/mise
COPY config/mise-config.toml /etc/skel/.config/mise/config.toml
# Claude Code のフック定義(ペインボーダーの状態表示を呼び出す)
RUN mkdir -p /etc/skel/.claude
COPY config/claude-settings.json /etc/skel/.claude/settings.json
# =============================================================================
# 7. Switch to devuser
# =============================================================================
USER devuser
WORKDIR /home/devuser
ENV HOME=/home/devuser
# =============================================================================
# 8. Oh My Zsh + zsh-completions
# =============================================================================
RUN sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended \
&& git clone https://github.com/zsh-users/zsh-completions ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-completions
# =============================================================================
# 9. mise + runtimes (node, python, go, java)
# =============================================================================
RUN curl https://mise.run | sh \
&& echo 'eval "$(~/.local/bin/mise activate zsh)"' >> /tmp/mise_init.sh
ENV PATH="$HOME/.local/bin:$HOME/.local/share/mise/shims:$PATH"
RUN mkdir -p $HOME/.config/mise \
&& cp /etc/skel/.config/mise/config.toml $HOME/.config/mise/config.toml \
&& mise install
# =============================================================================
# 10. Claude Code (native installer)
# =============================================================================
RUN curl -fsSL https://claude.ai/install.sh | bash
# =============================================================================
# 11. tmux plugin manager (tpm) + プラグイン本体
# =============================================================================
# tpm を clone するだけではプラグインは入らない(初回に手動で prefix+I が必要)。
# catppuccin が無いと status-right の @catppuccin_status_* が空に展開され、
# ステータスバーがほぼ空になる。tmux-sensible には prefix R/r の
# リロード・再描画バインドが含まれるので、これも入れておく。
RUN git clone https://github.com/tmux-plugins/tpm $HOME/.tmux/plugins/tpm \
&& cp /etc/skel/.tmux.conf $HOME/.tmux.conf \
&& $HOME/.tmux/plugins/tpm/bin/install_plugins \
&& rm $HOME/.tmux.conf
# gitmux: ステータスバーの Git 表示に必要(config/.tmux.conf が参照している)
# 設定ファイル自体は /etc/skel 経由で entrypoint が配置する
RUN go install github.com/arl/gitmux@latest
# Claude Code の状態を tmux のペインボーダーに出すフック用スクリプト
COPY --chown=devuser:devuser scripts/claude-tmux-state /home/devuser/.local/bin/claude-tmux-state
RUN chmod +x /home/devuser/.local/bin/claude-tmux-state
# =============================================================================
# 12. Entrypoint
# =============================================================================
COPY --chown=devuser:devuser scripts/entrypoint.sh /usr/local/bin/entrypoint.sh
USER root
RUN chmod +x /usr/local/bin/entrypoint.sh
USER devuser
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["sleep", "infinity"]