VSCodeをk8sにインストールしてリモートで使いたくなり、こちらの手順でインストールしてみました。ただ、これだけだとデバッグができないため、少しチャート(ci/helm-chart/)を変更してみましたので備忘録としてメモします。docker in dockerコンテナをサイドカーコンテナとして起動してcode-serverコンテナからデバッグ用のコンテナを起動できるようにする、がゴールです。
まず、デバッグ用のコンテナをdocker in dockerで立ち上げるため、以下のように少しvalue.yamlをいじりました。serviceにはデバッグ用コンテナ内で起動するアプリケーションサーバのポート及び外部からアクセスするためのポートを設定できるようにしています。また、postStartExecでcode-serverコンテナ内でdockerクライアントとdocker-composeをインストールするためのコマンドを定義しています。さらに、code-serverコンテナからdindコンテナにdockerコマンドでアクセスするためにDOCKER_HOST環境変数を定義しています。
service:
type: ClusterIP
port: 8080
debugTargetPort: 18000
debugPort: 18000
image:
repository: codercom/code-server
tag: '4.5.0'
pullPolicy: Always
postStartExec: "sudo curl -L https://github.com/docker/compose/releases/download/v2.6.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose \
&& sudo chmod +x /usr/local/bin/docker-compose \
&& curl -fsSL https://download.docker.com/linux/static/stable/x86_64/docker-20.10.17.tgz \
| sudo tar -xzC /usr/local/bin --strip=1 docker/docker"
extraVars:
- name: DOCKER_HOST
value: "tcp://localhost:2375"
あと、templates/deployment.yamlにはdindコンテナをサイドカーコンテナとして起動するための定義を追加するとともにcode-serverのコンテナ起動後にさきほどvalues.yamlで定義したコマンドを実行するようにlifecycleのpostStartを定義しています。ちなみに、code-serverコンテナ内でdockerコマンドを実行する際にフォルダをマウントすると、dindのコンテナ内のフォルダがマウントされる(関連ページ)ため、dindコンテナでも/home/coderにdataをマウントしています。
containers:
{{- if .Values.extraContainers }}
{{ tpl .Values.extraContainers . | indent 8}}
{{- end }}
- name: docker-dind
image: docker:20.10.17-dind
imagePullPolicy: IfNotPresent
volumeMounts:
- name: data
mountPath: /home/coder
resources:
requests:
cpu: 250m
memory: 256M
securityContext:
privileged: true
procMount: Default
env:
- name: DOCKER_TLS_CERTDIR
value: ""
- name: DOCKER_DRIVER
value: "overlay2"
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
lifecycle:
postStart:
exec:
command:
- sh
- -c
- {{ .Values.image.postStartExec }}
templates/service.yamlには前述したデバッグコンテナにアクセスするためのポートの定義を追加します。
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
- port: {{ .Values.service.debugPort }}
targetPort: {{ .Values.service.debugTargetPort }}
protocol: TCP
name: http-for-debug
これでターミナルからdockerコマンドが使えるようになりますので、例えばPHPならばソースフォルダをマウントしてアプリのコンテナを起動すれば動作を確認しながらソースを編集できます。ただ、dindで立ちあげたデバッグコンテナ内ではなぜかパッケージのインストールなど外部にアクセスするときにタイムアウトが頻発してしまう問題があった(こちらによると類似した現象がGitLab CIでも発生している)ため、コンテナのイメージビルド及びコンテナの実行時にはホストネットワークモードを利用するようにしました。具体的には、以下のようなdocker-compose.yamlを作成してビルド、コンテナ実行をしました。
version: '2'
services:
devserver:
container_name: 'devserver'
build:
context: .
network: host
command: tail -f /dev/null
expose:
- "18000"
network_mode: host
volumes:
- .:/workspace
user: "1000:1000"
例えば、ElixirのPhoenixで作成したWEBアプリのデバッグ用コンテナを使う場合のDockerfileの例としては以下のようになります。
FROM elixir:1.13.4-slim
WORKDIR /workspace
RUN apt-get update -y && apt-get install -y \
inotify-tools \
make \
build-essential \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN adduser --gecos '' --disabled-password coder
USER coder
RUN mix local.hex --force
RUN mix local.rebar --force
RUN mix archive.install --force hex phx_new
デバッグコンテナ内でPhoenixアプリを起動する際にはこちらのページのようにポートの設定を変更する必要があります。今回は18000番を指定したのでdev.exsのポート設定を以下のようにしました。
config :chat, ChatWeb.Endpoint,
# Binding to loopback ipv4 address prevents access from other machines.
# Change to `ip: {0, 0, 0, 0}` to allow access from other machines.
http: [ip: {0, 0, 0, 0}, port: 18000],
check_origin: false,
code_reloader: true,
debug_errors: true,
secret_key_base: "xxxx",
watchers: [
# Start the esbuild watcher by calling Esbuild.install_and_run(:default, args)
esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]}
]