SAM CLI の Docker内(--use-container) ビルドをProxy環境下で実施する方法



2017年頃からサーバレスに浸っている、小西啓介です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/40049/f960c804-b36c-2893-1ae5-eed795f20606.png)


# SAM CLIでは、Lambdaに近い環境でビルドできる

SAM(Serverless Application Model) CLI のビルドコマンド(`sam build`)には、
Lambda用の `npm` や `pip` などで、アーキテクチャ(WindowsかLinux等)に依存するモジュールが有る場合に対応する
オプション (`--use-container`)がある。

このオプションを使用すると、通常、実行環境(windows等)で行うビルド処理を、Lambda(Amazon Linux) に近い
Docker環境内で行うようなるため、コンパイルを伴うような場合でも問題なく（※文末参照 2020/07/10追記）、Lambda用のリソースを作成することが可能となる。

# Proxyの憂鬱

ここにも、毎度おなじみのProxyの憂鬱がある。

```powershell
PS C:\Users\komikoni\workspace\sam app> sam build --use-container

Building function 'NodeFunc'
//./pipe/docker_engine
//./pipe/docker_engine
//./pipe/docker_engine

Fetching lambci/lambda:build-nodejs12.x Docker container image......
Mounting C:\Users\komikoni\workspace\sam app\node-function as /tmp/samcli/source:ro,delegated inside runtime container
//./pipe/docker_engine
//./pipe/docker_engine
//./pipe/docker_engine
//./pipe/docker_engine
//./pipe/docker_engine

Build Failed
Error: NodejsNpmBuilder:NpmInstall - NPM Failed: npm ERR! code ENOTFOUND
npm ERR! errno ENOTFOUND
npm ERR! network request to https://registry.npmjs.org/jsonwebtoken failed, reason: getaddrinfo ENOTFOUND registry.npmjs.org
npm ERR! network This is a problem related to network connectivity.
npm ERR! network In most cases you are behind a proxy or have bad network settings.
npm ERR! network
npm ERR! network If you are behind a proxy, please make sure that the
npm ERR! network 'proxy' config is set properly.  See: 'npm help config'

npm ERR! A complete log of this run can be found in:
```


実行環境が、Proxy経由でインターネットに繋がっている場合、
当然、Docker内からもProxy経由でしかインターネットに繋ぐことが出来ない為、
Docker インスタンスに対して、環境変数等でProxy設定を与えてあげる必要がある。

しかし、SAM　のビルドコマンド(`sam build`)で、実行する場合、動的にDockerインスタンスを作成し
ビルドが終了すると自動的に削除される為、Proxyを与えることが難しかった。

※Docker Desktopのproxy設定は、Docker Imageをダウンロードする際に使用するProxy設定で、Docker Image内には適用されない。

この課題は、以下のIssueに上がっている。

- [sam build --use-container fails hello\_world when behind proxy. · Issue #913 · awslabs/aws-sam-cli · GitHub](https://github.com/awslabs/aws-sam-cli/issues/913)

そこで、SAM では、  Docker SDK >= 3.7.0 でサポートされた、**global docker configuration file.** 機能を使って、
外部からProxy設定を可能となるよう対応が行われた。

- [Docker proxy config by cooper3330 · Pull Request #1196 · awslabs/aws-sam-cli · GitHub](https://github.com/awslabs/aws-sam-cli/pull/1196)

既に、上記のPull Request は、マージされてReleaseされているですが、
特にドキュメント上には、記載がなさそうなので、ここに書き残したいと思います。

# global docker configuration file の設定

設定方法は、以下の記事 @2fbCvmiYKX さんの記事や Dockerのドキュメントが詳しいが、

- [Docker Desktop for Windows の proxy 設定 - Qiita](https://qiita.com/2fbCvmiYKX/items/c6aab333364af25fd924)
- [Configure Docker to use a proxy server | Docker Documentation](https://docs.docker.com/network/proxy/#configure-the-docker-client)


`%USERPROFILE%\.docker\config.json` の編集し

```js:変更前
{
  "auths": {
    "https://index.docker.io/v1/": {}
  },
  "credsStore": "desktop",
  "experimental": "enabled",
  "stackOrchestrator": "kubernetes"
}
```

を以下のように修正する


```js:変更後
{
  "auths": {
    "https://index.docker.io/v1/": {}
  },
  "credsStore": "desktop",
  "experimental": "enabled",
  "stackOrchestrator": "kubernetes",
  "proxies": {
    "default": {
      "httpProxy": "http://proxy.example.com:8080",
      "httpsProxy": "http://proxy.example.com:8080",
      "noProxy": "no_proxy.example.com"
    }
  }
}
```

これで、以下の通り、Proxy環境下であっても、SAM CLI の Docker内(--use-container) ビルドを実施することが、可能となる。

```powershell
PS C:\Users\komikoni\workspace\sam app> sam build --use-container

Starting Build inside a container
Building function 'AuthFunc'
//./pipe/docker_engine
//./pipe/docker_engine
//./pipe/docker_engine

Fetching lambci/lambda:build-nodejs12.x Docker container image......
Mounting C:\Users\komikoni\workspace\sam app\node-function as /tmp/samcli/source:ro,delegated inside runtime container
//./pipe/docker_engine
//./pipe/docker_engine
//./pipe/docker_engine
//./pipe/docker_engine
//./pipe/docker_engine
//./pipe/docker_engine
Running NodejsNpmBuilder:NpmPack
Running NodejsNpmBuilder:CopyNpmrc
Running NodejsNpmBuilder:CopySource
Running NodejsNpmBuilder:NpmInstall
Running NodejsNpmBuilder:CleanUpNpmrc
Building function 'NodeFunc'

Fetching lambci/lambda:build-nodejs12.x Docker container
image..............................................................................................................................................................................................................
Mounting C:\Users\komikoni\workspace\sam app\node-function as /tmp/samcli/source:ro,delegated inside runtime container
//./pipe/docker_engine
//./pipe/docker_engine
//./pipe/docker_engine
//./pipe/docker_engine
//./pipe/docker_engine
//./pipe/docker_engine
Running NodejsNpmBuilder:NpmPack
Running NodejsNpmBuilder:CopyNpmrc
Running NodejsNpmBuilder:CopySource
Running NodejsNpmBuilder:NpmInstall
Running NodejsNpmBuilder:CleanUpNpmrc
Building function 'PythonFunc'
//./pipe/docker_engine
//./pipe/docker_engine

Fetching lambci/lambda:build-python3.6 Docker container image..............................................................................................................................................................................................................
Mounting C:\Users\komikoni\workspace\sam app\python-function as /tmp/samcli/source:ro,delegated inside runtime container
//./pipe/docker_engine
//./pipe/docker_engine
//./pipe/docker_engine
//./pipe/docker_engine
//./pipe/docker_engine
//./pipe/docker_engine

Build Succeeded

Built Artifacts  : .aws-sam\build
Built Template   : .aws-sam\build\template.yaml

Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Deploy: sam deploy --guided

Running PythonPipBuilder:ResolveDependencies
Running PythonPipBuilder:CopySource
PS C:\Users\komikoni\workspace\sam app> 
```

# 実行ファイルのパーミッションについて (2020/07/10追記)　→ (2020/10/30解消)

一点書き忘れました、 `--use-container`　を利用した場合、コンパイルを伴うビルドも可能ですが、実行ファイルに関しては、問題があります。
基本的に、Windowsでは、パーミッション設定が行えずZip化する場合もパーミッションが付与されない為、Lambda内で実行する際にパーミッションエラーとなります。

- [fix: Update external\_attr attribute on the zipfile.ZipInfo before zipping by spaceraccoon · Pull Request #1986 · awslabs/aws-sam-cli](https://github.com/awslabs/aws-sam-cli/pull/1986)


上記の通り、Issueが上がっていますが、2020/07/10現在まだマージされておらず、
以下のいずれかの方法を取る必要があります。

1. Windowsから、`--use-container`を使うのではなく、LinuxにSAM を入れでビルドを行う。
2. sam build 、 sam deploy やcfn deploy を使わず、自分でZip化し、パーミッションを設定する。
3. Lambda上で、パーミッションを変更する。

※ `3.` について、Zipで上げたファイルの自体は、領域としてパーミッション変更できない為、
一度 `/tmp` にコピーしてからパーミッションを変更して、実行する必要があります。

早くIssueが取り込まれることを期待したいですね。


## ついに取り込まれて解消しました。

[SAM CLI Release 1.7.0](https://github.com/aws/aws-sam-cli/releases/tag/v1.7.0) で
2020/10/30に解消しました。

> 7d5101a - Fix: Missing Unix Permission Bits for Artifact ZIP Created in Windows (#2193)

と記載がある通り、上記Issueが解消しました。（実際は別Issue のGo周りの対応で解消された）