🧹

Dev Containerで開発環境の年末大掃除を行う

2023/12/09に公開

はじめに

1年目の@i_doです。RetailAI Adventurers Advent Calendar 2023の10日目の記事を書かせていただきます。
今まで何となく使っていたvscodeの拡張機能、devcontainerについて理解を深め、開発環境の年末大掃除をしたいと思います。なお、家の大掃除はまだしていません。

Dev Containerとは

DevContainerとは、VS Codeの拡張機能の1つです。DevContainerを使うことで、開発環境を丸ごとコンテナ化することができます。
数あるメリットの中でも個人的に嬉しいのは、local環境を汚さずに開発ができると言う点です。また、開発環境に再現性が生まれるのでgithubなどに上げておけば、PCを変えても1から設定しなおす必要がなくなります。

どう言う仕組みか

では、Dev Containerはどんな仕組みで動いているのでしょう。
Dev containerのドキュメントを見に行くと、冒頭にデカデカと解説図が。

ビルドしたコンテナに、データをボリュームとしてマウントしてコンテナ内でそのデータを参照すると言うような感じで動いているみたいです。

Dev Containerに必要なもの

なんとなく仕組みがわかったところで、実際に立ち上げてみます。devcontainerに必要なものは下記のファイルです。

├── .devcontainer
│   ├── devcontainer.json
│   ├── (Dockerfile)
│   └── (docker-compose.yml)

今回は自分で1から環境構築してみたいので全部作成します。

作成

それではDev Containerを作成してみます。
普段ローカルで開発しているプロジェクトの中に作成していきます。今回はpythonで開発している環境をdevcontainer化します。

Dockerfile
FROM --platform=linux/arm64/v8 debian:trixie-20231120-slim

ARG USERNAME=vscode
ARG GROUPNAME=developer
ARG UID=1000
ARG GID=1000

RUN apt-get update \
&& apt-get install python3 -y \
&& apt-get install python3-pip -y
RUN groupadd -g $GID $GROUPNAME && \
    useradd -m -s /bin/bash -u $UID -g $GID $USERNAME

USER $USERNAME

WORKDIR /home/vscode
docker-compose.yml
version: "3.8"

services:
  devcontainer:
    build:
      context: ..
      dockerfile: .devcontainer/Dockerfile
    volumes:
      - ..:/home/vscode:cached
    command: /bin/sh -c "while sleep 1000; do :; done"
    user: vscode
volumes:
  ${project-name}:
devcontainer.json
{
    "name": "proj-{$project-name}",
    "service": "devcontainer",
    "dockerComposeFile": "docker-compose.yml",
    "workspaceFolder": "/home/vscode",
    "customizations": {
        "vscode": {
            // Add the IDs of extensions you want installed when the container is created.
            "extensions": [
                "GitHub.vscode-pull-request-github",
		"ms-python.python"
            ]
        }
    },
    "remoteUser": "vscode",
    "features": {
        "ghcr.io/devcontainers/features/github-cli:1": {},
    }
}

コードについて

docker-compose.yml

command: /bin/sh -c "while sleep 1000; do :; done"

上記のコードでコンテナを永続的に稼働させています。
これがないと、

Error response from daemon: Container {$containerID} is not running

というエラーが出て起動できません。

devcontainer.json

"customizations": {
        "vscode": {
            // Add the IDs of extensions you want installed when the container is created.
            "extensions": [
                "GitHub.vscode-pull-request-github",
                "ms-python.python"
            ]
        }
    },

ここで、devcontainerを起動した時にインストールしておく拡張機能を入れておきます。このプロジェクトはpythonを扱うので、pythonの拡張機能を入れています。

"features": {
        "ghcr.io/devcontainers/features/github-cli:1": {},
    }

ここでgitコマンドが使えるようにしています。(pythonも使いたかったけど起動できなかったので、コマンドでインストールすることに。osの問題?)

Dockerfile

RUN apt-get update \
&& apt-get install python3 -y \
&& apt-get install python3-pip -y
RUN groupadd -g $GID $GROUPNAME && \
    useradd -m -s /bin/bash -u $UID -g $GID $USERNAME

ここでpython, pipのインストールと、コンテナ内で利用するユーザーを作成しています。

P.S. インストールしたpipのコマンドが使えなかったので調べた結果、イメージでの問題らしい。
bullseyeに変えたところ無事起動

- debian:trixie-20231120-slim

+ debian:bullseye-slim

https://github.com/orgs/community/discussions/61327

苦労した点

苦労した点は、とにかく実行ユーザーの設定というか理解です。まず、コンテナの実行ユーザーですが、デフォルトではrootとなります。これによって何が起こるかというと、

  1. コンテナ内で作成したファイルの所有者はrootになる。
  2. セキュリティ面で良くない(コンテナが乗っ取られたらホストに攻撃される可能性)
    2に関しては、言うまでもないですが、1に関して、コンテナ内で作成したファイルをホスト側で操作したいと思った時に(マウントとかしていた時)root権限がないと操作できません。
    そこで、上記のコードでは、
RUN groupadd -g $GID $GROUPNAME && \
    useradd -m -s /bin/bash -u $UID -g $GID $USERNAME

この部分で一般ユーザーを作成しているというわけです。

無事起動

この設定で、コマンドパレットから、> Dev Containers: Reopen in Containerと入力して起動します。無事起動できました!拡張機能もコマンドもきちんと入っています。

終わりに

出現してから数年経っているdevcontainerですが、今までは用意されていたイメージで作成していましたが、今回勉強して少し自由度が上がりました。
学生の時はずっとローカル環境で開発していたので、使っていたPCを見てみるとローカル環境がぐちゃぐちゃになっていました笑 こちらも大掃除したいと思います。

入社して早くも1年が経ちますが、もっともっと開発ができるようになるために来年も勉強していきたいと思います。
読んでいただきありがとうございました。皆様よいお年を!

参考サイト

https://qiita.com/Spritaro/items/602118d946a4383bd2bb
https://code.visualstudio.com/docs/devcontainers/containers

Discussion