UbuntuにDockerをインストールし、tlsを使ったリモート接続の設定を行う

# UbuntuにDockerをインストールし、tlsを使ったリモート接続の設定を行う

[こちら](https://ttis.croud.jp/?uuid=72cb3eef-3aa9-4c2d-8390-690a2f1c69d7)でも同じ記事を書いています

## １．Dockerのインストール

UbuntuにDockerをインストールするためには以下のコマンドを実行します
面倒がないようにコピペ一発で全て行うようにしてあります

```bash
sudo apt -y install apt-transport-https ca-certificates software-properties-common && \
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - && \
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" && \
sudo apt install -y docker-ce
```

## ２．Dockerの起動設定

OS起動時に自動起動させ、その場でも起動させます

```bash
sudo systemctl enable docker
sudo systemctl start docker
```

## ３．動作確認

デフォルトではDockerへの接続にroot権限が必要です

```bash
sudo docker ps
```

## ４．一般ユーザでDockerを使えるようにする

以下のコマンド実行後、ログインし直すと使えるようになります

```bash
sudo echo usermod -aG docker `logname`
```

確認

```bash
docker ps
```

## ５．tlsによる接続

ここからが面倒な部分になります
オレオレ証明書を作成しサーバとクライアントに配る必要があるのですが、これをやるのに一手間二手間かかります
余りに面倒なので、コマンド一発で終わるように、途中の入力を全てスキップするスクリプトを作成しました

### 5.1 証明書の作成

コマンドの説明はこちらを確認してください
https://github.com/SoraKumo001/docker-tls

リモートからで接続するための証明書を作成します

```bash
curl -s https://raw.githubusercontent.com/SoraKumo001/docker-tls/master/docker-tls.sh | \
sudo bash
```

接続の際にホスト名を正確に設定したい場合は以下のようにドメイン名やIPを指定します

```bash
curl -s https://raw.githubusercontent.com/SoraKumo001/docker-tls/master/docker-tls.sh | \
sudo bash -s DNS:host.example.com,IP:10.1.1.1
```

#### 　5.1.1 生成されるファイル

- プライベートキー
/etc/docker/certs/private-key.pem

- Dockerデーモン用ファイル
/etc/docker/certs/ca.pem 
/etc/docker/certs/server-key.pem 
/etc/docker/certs/server-cert.pem

- クライアント用ファイル
~/.docker/ca.pem 
~/.docker/cert.pem 
~/.docker/key.pem

　WindowsやMacの各環境でリモート接続する場合は、クライアント用ファイルをユーザディレクトリの.dockerフォルダにコピーします

#### 　5.1.2 プライベートキーに関して

　証明書の自動生成スクリプトはプライベートキーを使い回すように作ってあります
　そのため証明書を再発行しても、クライアントの証明書は配り直す必要がありません
　また、既存のプライベートキーを他のサーバの同じ位置にコピーした状態で証明書を作成すると、同じクライアント用ファイルで複数のサーバに接続可能になります

　完全な作り直しが必要な場合は、プライベートキーを手動で消してください

### 5.2 サービスの設定変更

- ファイルの書き換え  
**/lib/systemd/system/docker.service** の**ExecStart**を以下のように書き換えます  
この設定によって、tlsによるTCP接続を受け入れるようになります
ちなみに外部公開サーバをtlsを使わずにTCP接続を受け入れる設定になっていると、いつの間にかビットコインの製造工場と化す可能性があるので気をつけてください

```bash
ExecStart=/usr/bin/dockerd --tlsverify --tlscacert=/etc/docker/certs/ca.pem --tlscert=/etc/docker/certs/server-cert.pem --tlskey=/etc/docker/certs/server-key.pem -H tcp://0.0.0.0 -H fd:// --containerd=/run/containerd/containerd.sock
```

- 手動で編集するのが面倒な場合  
以下のコマンドを貼り付ければ書き換えが完了します

```bash
sudo sed -i "s/^ExecStart=.*/ExecStart=\/usr\/bin\/dockerd \
--tlsverify --tlscacert=\/etc\/docker\/certs\/ca.pem \
--tlscert=\/etc\/docker\/certs\/server-cert.pem \
--tlskey=\/etc\/docker\/certs\/server-key.pem \
-H tcp:\/\/0.0.0.0 -H fd:\/\/ \
--containerd=\/run\/containerd\/containerd.sock/" \
/lib/systemd/system/docker.service

```

### 5.3 サービスの更新

```bash
sudo systemctl daemon-reload && sudo systemctl restart docker
```

### 5.4 tlsによる接続確認

ここまでのサービス設定で-Hを使ってアドレス指定で接続する場合はtls接続が必須になっています
そのため--tlsを指定しないと接続できません
--tlsverifyにした場合は、接続時にドメイン名を検証するようになります

```bash
docker --tls -H localhost ps
```

```bash
docker --tlsverify -H localhost ps
```


### 5.5 リモートでのDockerイメージの転送

Dockerのコマンドには、Dockerイメージをパイプで受け渡す機能があるので、以下のようにするとDockerHubを経由しなくてもリモートでイメージを転送できます

```bash
docker save イメージ名(複数指定可能) | docker --tls -H サーバ名 load
```

ローカルで作成したイメージやCI/CDでビルドしたものを転送する場合に便利です
小規模なものならこれで簡単にデプロイが可能です

### 5.6 docker-composeから接続する場合

証明書作成時に指定したホスト名と一致しないと接続できないので注意してください

```bash
docker-compose --tlsverify -H ホスト名:2375 以下通常コマンド
```

## ６．まとめ

　証明書の発行させしてしまえば、リモートで簡単にDockerを操作することが出来るようになります
　あとはコンテナを送りつけて動かせば大体何でも出来るようになります
　ただし、パプリックなリポジトリに証明書を入れて公開するようなミスには気をつけてください
　公開は後悔を生みます