サーバー上のDockerのbuild時にGithubのprivateレポジトリからpip installする方法

# 内容

- `ssh-agent`を使ってサーバー上でGithubにssh接続する
- Dockerの`Build-time secrets`と`ssh-keyscan`を使ってbuild時にGithubにssh接続する

具体例としてDockerのbuild中にプライベートレポジトリにあるパッケージを `pip install` する。(※ この`pip install`の具体例だけではなくprivateレポジトリとのやり取りを行う処理の全般に使える。)

環境は以下の通り。(ただし、Macであれば他は問題にならないはず)

- Mac OS (10.14)
- サーバー: Ubuntu 16.04
- Docker 18.09 or higher (必須)

# ssh-agentを使ってサーバー上でGithubにアクセス

普段手元のPCで使っている秘密鍵をサーバー上でも使えるようにする。

まずは秘密鍵を登録する。以下のコマンドで登録されているかどうかを確認できる。まだ何も登録していないので何も登録されていない。

```
$ ssh-add -l
The agent has no identities.
```

ここで秘密鍵の登録を行う。サーバー上でGithubとのやり取りを行いたいのでGithubに接続できる秘密鍵を選択する。Githubにsshアクセスできない方は[GitHubでssh接続する手順~公開鍵・秘密鍵の生成から~](https://qiita.com/shizuma/items/2b2f873a0034839e47ce)でまずは登録を行う。

```
$ ssh-add ~/.ssh/id_rsa
```

これで登録ができるので、以下のように登録されていることが確認できる。

```
$ ssh-add -l
2048 xxx xxx/.ssh/id_rsa (RSA)
```

以上で秘密鍵が登録できたので、普段のssh接続のときに`-A`のオプションをつけてアクセスする。

```
$ ssh -A xxx
```

サーバー上で以下のように打って、接続が確認できたら完了。

```
$ ssh -T git@github.com
Hi xxx! You've successfully authenticated, but GitHub does not provide shell access.
```


# Docker build上でprivateレポジトリからpip install


## Dockerfile サンプル


```
# syntax=docker/dockerfile:1.0.0-experimental

FROM ubuntu:16.04
ENV DEBIAN_FRONTEND noninteractive

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    build-essential \
    curl \
    git \
    libbz2-dev \
    libreadline-dev \
    libsqlite3-dev \
    libssl-dev \
    libcairo2-dev \
    libgirepository1.0-dev \
    make \
    openssh-client \
    python-dev \
    python-pip \
    vim \
    wget \
    zip \
    zlib1g-dev && \
    rm -rf /var/lib/apt/lists/*

ENV HOME /root

RUN git clone git://github.com/yyuu/pyenv.git $HOME/.pyenv
RUN git clone https://github.com/yyuu/pyenv-virtualenv.git $HOME/.pyenv/plugins/pyenv-virtualenv

ENV PYTHON_VERSION 3.6.8
ENV PYTHON_ROOT $HOME/local/python-$PYTHON_VERSION
ENV PYENV_ROOT $HOME/.pyenv
ENV PATH $PYENV_ROOT/shims:$PYENV_ROOT/bin:$PATH

RUN pyenv install 3.6.8
RUN pyenv global 3.6.8

RUN mkdir -m 700 $HOME/.ssh
RUN ssh-keyscan github.com > $HOME/.ssh/known_hosts
RUN --mount=type=ssh pip install git+ssh://git@github.com/xxx/xxx.git@vx.x.x
```

これを以下のようにbuildする。

```
$ export DOCKER_BUILDKIT=1
$ docker build -t xxx --ssh default .
```

## Build-time secrets

`docker build`を行うときに`secrets`を使えるようになる機能。 Docker 18.09以降のバージョンが必要。以下のように`Dockerfile`の先頭に`# syntax`の記述をすることと、対象となる行に`--mount=type=ssh`をつけることでssh接続が実現できる。

```
# syntax=docker/dockerfile:1.0.0-experimental

RUN --mount=type=ssh xxx
```

また、実行時には以下のようにする。

```
$ export DOCKER_BUILDKIT=1
$ docker build -t xxx --ssh default .
```

## ssh-keyscan

上記の処理だけだと接続時に以下のようなエラーが出てしまう。これは`known_hosts`がうまく設定されていないからである。 

```
Host key verification failed.
fatal: Could not read from remote repository.
Please make sure you have the correct access rights and the repository exists.
```

`ssh-keyscan`を使って以下のように`known_hosts`を設定してあげることでエラーは解消される。

```
RUN mkdir -m 700 $HOME/.ssh
RUN ssh-keyscan github.com > $HOME/.ssh/known_hosts
```

`ssh-keyscan`を使うためには`openssh-client`を`apt-get`で入れておいてあげる必要があることに注意。




# 参考

- [ssh-agentの使い方](https://qiita.com/isaoshimizu/items/84ac5a0b1d42b9d355cf)
- [Docker Engine 18.09 から使える Build-time secrets を試してみた](https://blog.manabusakai.com/2018/12/docker-build-secret/)
- [DOCKER BUILD LEARNS ABOUT SECRETS AND SSH AGENT FORWARDING](http://blog.oddbit.com/post/2019-02-24-docker-build-learns-about-secr/)
- [Build secrets and SSH forwarding in Docker 18.09](https://medium.com/@tonistiigi/build-secrets-and-ssh-forwarding-in-docker-18-09-ae8161d066)