VSCodeのdevcontainerにSAM CLIをインストールしlocal invokeする

dockeraws

VSCodeのdevcontainerにAWS SAM CLIをインストールしてDockerを用いたlocal invokeもできるようにする。

VSCodeのRemote DevelopmentでSageMakerのコンテナ環境でモデルを開発する - sambaiz-net

HomebrewとSAM CLIのインストール

手順に従ってbrewでインストールする。

  • Homebrewがsudoとgit、psを必要とするのでインストールする
  • デフォルトのrootでHomebrewをインストールするとDon’t run this as root!になるので non-root userを作って そのユーザーで実行する
  • brew install aws-sam-cliでsamはインストールできているのにexit 1して失敗するのを握り潰している
  • 次にdockerが必要となるので入れている
FROM debian:buster

ARG USERNAME=vscode
ARG USER_UID=1000
ARG USER_GID=$USER_UID

# Create the user
RUN groupadd --gid $USER_GID $USERNAME \
    && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \
    #
    # [Optional] Add sudo support. Omit if you don't need to install software after connecting.
    && apt-get update \
    && apt-get install -y sudo \
    && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
    && chmod 0440 /etc/sudoers.d/$USERNAME

USER $USERNAME
WORKDIR /home/$USERNAME

# Install Homebrew & SAM CLI
RUN sudo apt-get update && sudo apt-get install -y curl git procps && \
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" && \
    eval $(/home/linuxbrew/.linuxbrew/bin/brew shellenv) && \
    echo "eval \$($(brew --prefix)/bin/brew shellenv)" >>~/.profile && \
    brew tap aws/tap && (brew install aws-sam-cli docker; true)

実行できるか確認したところnot foundになってしまいインストールに失敗したのかと思ったが、 PATHが通ってないだけで、-lフラグを付けると~/.profileなどが読まれてコマンドが実行できるようになった。

$ docker build -t sam-image .
$ docker run sam-image sam --version
docker: Error response from daemon: OCI runtime create failed: container_linux.go:346: starting container process caused "exec: \"sam\": executable file not found in $PATH": unknown.

$ docker run -it hogea /bin/sh -l -c "sam --version"
SAM CLI, version 1.6.2

ということでsettingsに次の項目を追加した。

{
  "settings": { 
    ...
    "terminal.integrated.shellArgs.linux": ["-l"]
  }
}

Docker in Dockerの設定

initしてローカルで実行したところ次のようなエラーが出た。SAM CLIはローカル実行や--use-containerでのビルドのためにDockerを用いる。

$ sam local invoke HelloWorldFunction --event events/event.json
...
Error: Running AWS SAM projects locally requires Docker. Have you got it installed and running?

そこでdevcontainer.jsonのmountsにdocker.sockを追加し、コンテナ内からホストのDockerデーモンにアクセスできるようにする。

{
    ...
    "mounts": [
        "source=${localEnv:HOME}/.aws,target=/home/vscode/.aws,type=bind,readonly",
        "source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
    ],
    "postCreateCommand": "sudo chown vscode /var/run/docker.sock"
}

Dockerコマンドでデーモンにアクセスできることを確認。

$ docker ps
CONTAINER ID        IMAGE                                           COMMAND                  CREATED             STATUS              PORTS               NAMES
...

Docker for MacでのMounts denied

sam local invokeしたところ次のエラーが出た。

$ sam local invoke
...
docker.errors.APIError: 500 Server Error: Internal Server Error ("b'Mounts denied: \nThe path /workspaces/*** is not shared from the host and is not known to Docker.\nYou can configure shared paths from Docker -> Preferences... -> Resources -> File Sharing.\nSee https://docs.docker.com/docker-for-mac for more info.'")

FILE SHARINGの設定に対象のパスを追加した。

FILE SHARINGの設定

/var/task/***: no such file or directory

再びsam local invokeしたところ次のエラーに変わった。sam buildは成功していて対象のパスにはファイルが存在する。

Mounting /workspaces/***/.aws-sam/build/*** as /var/task:ro,delegated inside runtime container
START RequestId: 79793925-12c5-175d-cfb4-5e1e0523f757 Version: $LATEST
fork/exec /var/task/***: no such file or directory: PathError

リモートのDockerを使う場合は、–docker-volume-basedirでリモート、つまりホストの方のパスを指定する必要がある。そこで次の環境変数を定義してホストのパスを渡せるようにした。

{
  "remoteEnv": {
    "HOSTPWD": "${localEnv:PWD}"
  }
}
$ sam local invoke --docker-volume-basedir ${HOSTPWD}/.aws-sam/build

参考

AWS SAM in a Docker Dev Container – avdi.codes