空雲 Blog

Eye catchUbuntuにDockerをインストールし、tlsによるリモート接続を行う

publication: 2024/03/10
update:2024/03/10

昔作成したコンテンツのバックアップ用記事です

Dockerのインストール

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

1curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg && \
2echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
3 $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null && \
4sudo apt update && sudo apt install -y docker-ce

Dockerの起動設定

1sudo systemctl enable docker
2sudo systemctl start docker

動作確認

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

1sudo docker ps

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

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

1sudo usermod -aG docker `logname`

確認

1docker ps

tlsによる接続

Dockerにはリモート作業時、パスワード認証のような機能はありません
httpsを利用して、暗号化ついでにコマンドを勝手に実行されないように制限をかける必要があります

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

証明書の作成

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

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

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

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

1curl -s https://raw.githubusercontent.com/SoraKumo001/docker-tls/master/docker-tls.sh | sudo bash -s DNS:host.example.com,IP:10.1.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

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

また、既存のプライベートキーを他のサーバにコピーした状態で証明書を作成すると、クライアント用ファイルが使い回せるようになります

サービスの設定変更

  • ファイルの書き換え
    /lib/systemd/system/docker.service のExecStartを以下のように書き換えます

1ExecStart=/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

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

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

サービスの更新

1sudo systemctl daemon-reload && sudo systemctl restart docker

tlsによる接続確認

ホストを指定して接続する場合はtls接続が必須となっています
--tlsを指定しないと接続できません
--tlsverifyオプションにすると、接続時にドメイン名を検証するようになります

1docker --tls -H localhost ps

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

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

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

ローカルで作成したイメージやCI/CDでビルドしたものを転送する場合に便利です

docker-composeから接続する場合

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

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

Docker volumeのバックアップとリストア

何故か標準でバックアップ方法が存在しない

DockerはImageやConteinerは簡単にバックアップがとれるのに、何故かVolumeに関しては標準的なバックアップ方法が存在しません。ということでできる限り簡単な方法を考えてみました。

ネットで検索すると出てくる方法

VolumeをマウントするConteinerを作って、バックアップを作成する方法が多数ヒットします。ただ、残念なのはその出力先です。何故かバックアップファイルをConteiner内、もしくはDockerホスト上のディレクトリに作成していました。

それをやられるとリモートでコマンドを使った場合に、手元にバックアップが残りません。作成したバックアップを何らかの手段でさらに引き寄せる必要があります。非常に面倒です。

標準入出力を使おう

dockerコマンドは標準入出力でConteinerとデータをやりとりすることが出来ます。つまりバックアップファイルを標準出力に出すだけで、コマンドを実行した環境にバックアップ結果を吐き出すことが出来ます。

バックアップコマンドを作ってみる

以下のようなコマンドを実行すると、期待通りに動いてくれます。

によるリダイレクトはConteiner上ではなく、dockerコマンドを実行したローカル環境で働くからです。

バックアップコマンド

1docker run --rm -v [Dockerボリューム]:/backup busybox tar cvz -C /backup . > [バックアップファイル名.tar.gz]

リモートのDockerホストに対してボリュームのバックアップ

1docker -H [ホスト名] run --rm -v [Dockerボリューム]:/backup busybox tar cvz -C /backup . > [バックアップファイル名.tar.gz]

リモートのバックアップした場合も、もちろんローカル環境にバックアップをとることが出来ます。

リストアコマンドを作ってみる

リストアコマンド
dockerコマンドで-iを使い、標準入力を使えるようにします。

1docker run --rm -i -v [Dockerボリューム]:/backup busybox tar xvz -C /backup < [バックアップファイル名.tar.gz]

リモートのDockerホストに対してボリュームのリストア

1docker -H [ホスト名] run --rm -i -v [Dockerボリューム]:/backup busybox tar xvz -C /backup < [バックアップファイル名.tar.gz]

高速化したい

バックアップやリストアは出来るようになりましたが、もっと高速に処理したくなります。tarでzオプションを使うとgzipが使われますが、これをpigzのような並列処理対応のコマンドで置き換えれば、ホスト側のCPUのコア数に応じて高速化が見込めます。しかしざっと探したところ、pigzが入っている軽量Imageが見つかりません。もしかしたらどこかにあるかもしれませんが、探すより作った方が早いので作ることにしました。

pigz付きalpineのImageを作成します。
コマンドを書かなくても良いように、CMDも設定しておきます。

バックアップ用Imageを作成する

バックアップ

1FROM alpine
2RUN apk --no-cache add pigz
3CMD sh -c "tar cv -C /backup . | pigz"

リストア

1FROM alpine
2RUN apk --no-cache add pigz
3CMD sh -c "pigz -d | tar xv -C /backup"

Docker Hubに登録

個人アカウント名で置くのが微妙だったので、dktoolsという組織名を作りました。

・置き場所
バックアップ
https://hub.docker.com/r/dktools/backup
リストア
https://hub.docker.com/r/dktools/restore

・使い方
バックアップ

1docker run --rm -v [DOCKER-VOLUME]:/backup dktools/backup > backup.tar.gz

リストア

1docker run --rm -i -v [DOCKER-VOLUME]:/backup dktools/restore < backup.tar.gz

今のところパラメータ指定などはありませんが、気が向いたらそのうち機能を追加します。

まとめ

私の場合Dockerはtls接続でリモート管理しているので、バックアップをローカルに呼び寄せないと面倒なので、今回のようなものを作成しました。ちなみにsshのポートフォワードをしている場合も、リモートバックアップは可能です。ただtlsで直接接続している場合とポートフォワードでは、ポートフォワードの転送速度が数倍遅いので、出来ることならtls設定を入れた方が効率は上がります。