Windows11にDockerを使ってSAM + .NET6.0の開発環境を構築する

開発メンバーが増えてもDockerさえ準備すれば、SAM + .NET6.0の開発環境を構築できるように実験しました。

※筆者のPCはすでにWindows11に上げてしまっているので本記事はWindows11を前提としています。Windows10の場合はWSL2のインストール手順が異なりますのでご了承ください。

コンテナ技術を使わない場合の問題

コンテナ技術を使った開発環境の構築なんて今どき当たり前だとは思いますが、ネクタイ締めて仕事している私の職場はまだまだレガシー。

  • 構築作業に半日
    プロジェクトごとに開発環境の構築手順書が用意されており、開発メンバーが増えるたびに半日ほどかけて環境構築をしています。

  • 管理者権限がない
    開発PCの管理者権限を持たないメンバーもいるため、管理者権限無しで構築できるようにするには工夫が必要です。
    どうしても管理者権限が必要な場合もあるため、その場合はPC管理者に作業を依頼することも…
    最悪なのは、管理者権限有りでインストールしたメンバーとそうでないメンバーが混在すること。

  • 複数の環境が共存
    人数が少ないので複数のプロジェクトを兼務することもしばしば。
    各自の端末の中はあらゆるバージョンのSDKが入っており混沌としています。
    容量のひっ迫だけでなく、バージョン管理を適切に行う必要があります。

  • テストサーバを共有
    PostgreSQL, SQL Server, MySQLなど様々なデータベースを使っているため各自のPCに環境を構築するとストレージの消費やメモリの奪い合いなど大変なことになります。
    いちいちサービスを切り替えるのも面倒なのでデータベースやストレージは共有サーバを立てています。
    テーブル定義の変更やテストデータの管理はライブラリアンが取りまとめて行うことになっており、作業負担が増大しております。
    また、テストの再現性が低い点も大きな問題です。

改めてまとめてみるとひどいですね…
もしも、開発環境をコンテナ化してこれらが解消すればきっと私たちは幸せになれるはずです。
今回はDockerを使って開発環境を構築し、上記の問題が解決するか確認していこうと思います。

つくるもの

WindowsでDockerを利用する場合、Docker Desktop for Windowsを利用します。
一定の規模以上の企業では有料になるため、Docker Desktop for Windowsは使わずに環境を構築してみます。

※Docker Desktop for Windowsを使えばコンテナの管理が非常に簡単になります。仕事道具はケチらず、時間をお金で買うつもりで投資することをお勧めいたします。

Windows WSL2 Docker Containerを積み上げた図

以下の流れで進めていきます。

  1. Windows11にWSL2(ubuntu)をインストール
  2. WSL2(ubuntu)にDocker engineをインストール
  3. WSL2(ubuntu)にDockerFileを作成
  4. Windows11のVSCodeからContainerへリモート接続
    ※VSCodeのインストールは対象外。

Windows11にWSL2(ubuntu)をインストール

  1. PowerShell(管理者権限)で wsl --install を実行
  2. PCを再起動
  3. Ubuntuのインストール完了後、任意のユーザー名とパスワードを入力
  4. Ubuntuのターミナルでsudo apt-get updateを実行

sudo apt-get updateが失敗する
プロキシ環境下である場合やアンチウィルスソフトが原因であることが多いです。
私が試した環境の一つに、社内プロキシ + Symantec Endpoint Protection でうまく外部に接続できない事象が発生しました。

対処法
WSL2から外部への通信時に、ホストOSにフォワードプロキシを経由する方法が最も有効でした。
フォワードプロキシは「WSL2⇒ホストOS⇒社内プロキシ」といった具合に多段プロキシにする必要があります。

  1. Aache HTTP Server on Microsoft Windowsをダウンロード
    Apache x.x.xx Win64をダウンロードしてください。
  2. 任意のフォルダに展開
  3. 展開したフォルダ内の Apache24\conf\httpd.conf を編集

Define SRVROOT "c:/<展開したフォルダ>/apache24"
ServerRoot "${SRVROOT}"

Listen <任意のポート番号>

# 以下のModuleのコメントを外す
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_ftp_module modules/mod_proxy_ftp.so


# 末尾に追加
<IfModule proxy_module>
  ProxyRequests On
  ProxyVia On
  AllowCONNECT 443
  <Proxy *>
    Require all granted
  </Proxy>
  ProxyRemote * http://<社内プロキシHost>:<社内プロキシPort>
</IfModule>
  1. 管理者権限でPowerShell(CMDでもOK)を起動してサービスを登録
cd c:/<展開したフォルダ>/apache24
bin\httpd -t

bin\httpd -k install -n "<任意のサービス名>" -f "conf/httpd.conf"
  1. \\wsl$\Ubuntu\home<username>.bashrc の末尾に以下を追加
export http_proxy=http://$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}'):<httpd.confに設定した任意のポート番号>
export https_proxy=${http_proxy}

# ↓この方法が正解なのかは怪しいです(汗)
# ./docker/config.jsonに設定した内容はコンテナをcreateまたは新しく開始したタイミングでコンテナの環境変数として設定されます。
rm ~/.docker/config.json
echo {\"proxies\":{\"default\":{\"httpProxy\":\"${http_proxy}\",\"httpsProxy\":\"${https_proxy}\"}}} > ~/.docker/config.json
  1. WSL2のターミナル上で/etc/sudoersを編集
$ sudo visudo

# 以下を追加
Defaults  env_keep += "http_proxy"
Defaults  env_keep += "https_proxy"
Defaults  env_keep += "HTTP_PROXY"
Defaults  env_keep += "HTTPS_PROXY"

# 編集後はCtrl + x ⇒ y ⇒ Enter

WSL2(ubuntu)にDocker engineをインストール

Ubuntuのターミナルで作業を行います。
公式サイトに記載の手順を順に実行してください。

Set up the repositoryの1~3とInstall Docker Engineの1まででOKです。

追加作業としてWSL2起動時にDocker Daemonが起動するようにします。

  1. .bashrcの末尾に以下のコマンドを追記
# .bashrcの末尾に追記
# Start dockerd
sudo /etc/init.d/docker start
  1. パスワードの省略を追加
sudo visudo

# 末尾に追加
%docker ALL=(ALL)  NOPASSWD: /etc/init.d/docker

# 編集後はCtrl + x ⇒ y ⇒ Enter

WSL2(ubuntu)にDockerFileを作成

以前の記事と同等の環境を構築していきます。

「Dockerfile」という名前のファイルを \\wsl$\Ubuntu\home<ユーザー名><任意のフォルダ> に作成します。
※拡張子は不要です。

# Microsoftが配布している.NET6.0 SDKが入ったDocker Imageをベースにします
FROM mcr.microsoft.com/dotnet/sdk:6.0

# dotnet tool Install
RUN dotnet new -i Amazon.Lambda.Templates
ENV PATH="/root/.dotnet/tools:${PATH}"

# zip/unzip Install
RUN apt update \
 && apt -y install --no-install-recommends unzip zip \
 && apt clean \
 && rm -rf /var/lib/apt/lists/*

# AWS CLI Install
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
RUN unzip awscliv2.zip \
 && ./aws/install \
 && rm awscliv2.zip \
 && rm -r aws

# SAM CLI Install
RUN curl -OL https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip \
 && unzip aws-sam-cli-linux-x86_64.zip -d sam-installation \
 && ./sam-installation/install \
 && rm aws-sam-cli-linux-x86_64.zip \
 && rm -r sam-installation

※Dockerfileのベストプラクティスに則っていなかったので修正しました。

Windows11のVSCodeからContainerへリモート接続

  1. 上記で作成したDockerFileがあるフォルダでVSCode起動
  2. VSCodeからコンテナへのリモート接続を可能にするため、次の拡張機能「Remote - Containers」をインストール
  3. 画面左下のアイコン(>< ←こんなやつ)をクリック
  4. 画面上部にコマンドが表示されるので「Open Folder in Container…」を選択

ここまでの操作でDockerImageの作成、コンテナの起動、VSCodeからのリモート接続が完了した状態になります。
続いてVSCodeの拡張機能の設定を行います。

拡張機能はコンテナ別に設定できます。
コンテナにリモート接続したVSCodeのEXPLORERを見ると.devcontainer\devcontainer.jsonが作成されているので以下のように編集してください。
以降、VSCodeからコンテナに接続した際には自動的に拡張機能がインストールされた状態になります。

	// Add the IDs of extensions you want installed when the container is created.
	"extensions": [
		"ms-dotnettools.csharp",
		"amazonwebservices.aws-toolkit-vscode"
	]

配布

ここまでの手順が完了すれば手元にはDockerfileと.devcontainer\devcontainer.jsonが残っていると思います。
こちらを他の開発者に配布してください。

他の開発者が必要な作業は以下の通りです。

  1. (初回のみ)WSL2のインストール(要管理者権限)
  2. (初回のみ)Dockerのインストール
  3. (初回のみ)VSCodeにRemote-Containersをインストール
  4. \\wsl$\Ubuntu\home<ユーザー名><任意のフォルダ>にDockerfileと.devcontainer\devcontainer.jsonを配置
  5. VSCodeで \\wsl$\Ubuntu\home<ユーザー名><任意のフォルダ> を開く
  6. 画面左下のアイコン(>< ←こんなやつ)をクリック
  7. 画面上部にコマンドが表示されるので「Open Folder in Container…」を選択
    ※もし動かない場合はDocker Engineが起動していない可能性があるので、一度WSLにアクセスしてDocker Engineを起動させてください。

これで基本的な環境構築は完了です。

まとめ

Lambda開発を行うための.NET SDKが入ったコンテナだけを用意しましたが、実際には開発用データベース用のコンテナなども配布する必要があります。
複数のコンテナを同時に実行させるためにはDocker Composeを使いますが、今回はいったんここまでとします。

一度Dockerfileとdevcontainer.jsonを作成してしまえば、開発メンバーへの環境配布が簡単にできて、さらにWSL2インストール時を除けば管理者権限無しでも進められそうです。
構築作業コスト、管理者権限、環境の分離、(テストサーバ)の問題は概ね解消されそうです。

今まで食わず嫌いをしてしまっていましたが、もうDocker無しの開発には戻れなさそうです。

以上