リモート docker サーバの立ち上げ手順

この記事は自分用のメモです。

AlmaLinux 9 に docker をインストールし、ローカルネットワーク内の他のホストの docker client から操作するまでの手順をまとめます。

## 前提

- docker サーバ側
    - AlmaLinux 9
    - 「最小インストール」でOSをインストール済み
    - インターネットへ接続できる (docker 本体や docker イメージのダウンロードのため)
    - docker クライアント側のホストから管理者ユーザへの ssh 接続が可能
        - 特別に記載がない限り、このユーザへ ssh 接続して操作する
    - docker クライアント側のホストからユーザ `docker-cli` へ、公開鍵認証による ssh 接続が可能
        - このユーザが docker を使用できるように設定する予定
        - ユーザ名は自由。別名にする場合は適宜読み替えること。また、上記の「管理者ユーザ」と兼任でもよい
- docker クライアント側
    - Windows 10
    - Docker Desktop をインストール済みのため、`docker` コマンド (docker クライアントコマンド) を使用可能
        - ただし、Docker Desktop は終了しておくこと。設定やコマンドを誤ると `docker` コマンド使用時に  Docker Desktop が使われることがあるが、Docker Desktop が起動していなければエラーになるので誤りに気づくことができる
    - サーバ側への ssh 接続について下記のように設定されている
        - `~/.ssh/config` に、サーバ側への接続情報をホスト名 `remotedocker` として記載する
            - ホスト名は自由。別名にする場合は適宜読み替えること
        - `~/.ssh/config` に、秘密鍵 (`docker-cli` へのログインに使用するもの) のパスを指定するなどの方法で、ssh 接続時に鍵のパスの指定を省略できるようになっている
        - 秘密鍵 (`docker-cli` へのログインに使用するもの) にパスフレーズを設定しない、クライアント側で agent を活用するなどの方法で、パスフレーズの入力を必要としない状態にすることが望ましい
    - 特別に記載がない限り、Windows PowerShell でコマンドを実行する
    - ※おそらく他のOSでも同様の手順を踏める

## 1. docker のインストール

- 参考
    - https://higmasan.com/docker/almalinux-9-1%E3%81%ABdocker%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8B/

AlmaLinux に docker をインストールします。目的のためにはサーバだけインストールすればよいのですが、動作確認やトラブルシューティングで使用するため docker-ce-cli (クライアントコマンド) もインストールします。

### 1-1. リポジトリの登録

まず、dnf コマンドで docker をインストールできるようにするため、docker-ce が公開されているリポジトリを登録します。

```console
$ sudo dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
```

下記のコマンドで docker-ce-stable が登録されたことを確認します。

```console
$ dnf repolist
repo id                                                 repo の名前
appstream                                               AlmaLinux 9 - AppStream
baseos                                                  AlmaLinux 9 - BaseOS
docker-ce-stable                                        Docker CE Stable - x86_64
extras                                                  AlmaLinux 9 - Extras
```

### 1-2. docker のインストール

次のコマンドで、docker-ce (サーバ)、docker-ce-cli (クライアント)、その他拡張機能などをインストールします。

```console
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
```

### 1-3. docker の起動と動作確認

動作確認のため、以下のコマンドを使用することで、docker サーバを起動します。

```console
$ sudo systemctl start docker
```

サーバが起動したかどうかは `systemctl status docker` で確認します。下の例のように「 Active: active (running)」となっていれば起動しています。

```console
$ systemctl status docker
● docker.service - Docker Application Container Engine
     Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; preset: disabled)
     Active: active (running) since Sun 2025-05-18 17:55:37 JST; 1min ago
（略）
```

また、以下ようにコマンド `sudo docker info` で、クライアントからサーバへアクセスできることを確認しましょう。

```console
$ sudo docker info
Client: Docker Engine - Community
 Version:    28.1.1
 Context:    default
 Debug Mode: false
 Plugins:
  buildx: Docker Buildx (Docker Inc.)
    Version:  v0.23.0
    Path:     /usr/libexec/docker/cli-plugins/docker-buildx
  compose: Docker Compose (Docker Inc.)
    Version:  v2.35.1
    Path:     /usr/libexec/docker/cli-plugins/docker-compose

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 28.1.1
（略）
```

サーバへアクセスできていない場合、「Server:」の下にエラーメッセージが出力されます。

:::note warn
デフォルトでは docker サーバへは root 権限がないとアクセスできません。そのため、コマンド `docker info` を使用する際に `sudo` を使用しています。
:::

### 1-4. (任意) docker サーバが自動で起動するようにする

この設定をしない場合、シャットダウンや再起動をした際に、docker サーバは自動で起動しません。それで問題ない場合、この手順は不要です。

マシン起動時に docker サーバが自動で起動するようにするためには、`systemctl enable docker` を使用します。

```console
$ sudo systemctl enable docker
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
```

### 1-5. ユーザ `docker-cli` から docker を使えるようにする。

デフォルトでは root 権限がないと docker を使用できません。このままだと他のマシンからリモート接続して docker を使用する際にも root へのログインが必要になってしまい非常に使い勝手が悪いので、あらかじめ用意しておいた `docker-cli` ユーザからも docker を使用できるようにします。

:::note info
ユーザ名は自由です。公開鍵認証で ssh 接続できれば他のユーザでも構いません。
:::

グループ `docker` に属するユーザなら docker を使えるようになっているので、目的のユーザ (ここでは `docker-cli`) をグループ `docker` に加えます。

```console
$ sudo usermod -aG docker docker-cli
```

グループに追加されたことを確認します。

```console
$ cat /etc/group | grep docker
docker:x:993:docker-cli
docker-cli:x:1001:
```

これで次にログインしたときから `docker-cli` ユーザで docker を使えるようになっているので、確認してみます。成功すると、`sudo` 無しの `docker info` でサーバの情報を表示できるようになっています。

```console
$ su - docker-cli
$ docker info
（略）
```

## 2. クライアント側で、リモートサーバへアクセスできるよう設定する。

サーバ側は準備が整いました。サーバ側 (AlmaLinux) ではクライアントコマンド `docker` を使用して、docker を利用できる状態になっています。ここからは、クライアント側 (Windows) からクライアントコマンド `docker` を使用して、サーバ側の docker を利用できるようにします。

### 2-0. 前提条件の確認

クライアント側 (Windows) では、Docker Desktop をインストールしてあるため、`docker` コマンド自体は存在しています。ただし、Docker Desktop を起動していない状態を前提とします。

このとき、docker サーバが不在の状態なので、クライアント側で `docker info` を使用すると、次のように「Server:」の下にエラーメッセージが出力されます。

```console
> docker info
Client:
 Version:    27.2.0
 Context:    desktop-linux
 Debug Mode: false
 Plugins:
（中略）
Server:
ERROR: error during connect: Get "http://%2F%2F.%2Fpipe%2FdockerDesktopLinuxEngine/v1.47/info": open //./pipe/dockerDesktopLinuxEngine: The system cannot find the file specified.
errors pretty printing info
```

### 2-1. コンテキストの登録

- 参考
    - https://www.docker.com/blog/how-to-deploy-on-remote-docker-hosts-with-docker-compose/
    - https://qiita.com/s-inoue-git/items/e157c03c125d6a637180

ここではクライアント側にコンテキストとしてサーバ側への接続方法を登録することで、クライアント側からサーバ側の docker を操作できるようにします。

まずは現在登録されているコンテキストを確認します。

```console
> docker context ls
NAME              DESCRIPTION                               DOCKER ENDPOINT                             ERROR
desktop-linux *   Docker Desktop                            npipe:////./pipe/dockerDesktopLinuxEngine
```

コマンド `docker context create ...` を使用することで、コンテキストを登録します。ここでは、ホスト `remotedocker` へユーザ `docker-cli` として ssh 接続して docker を使用させるので、次のようになります。

```console
> docker context create remote --docker "host=ssh://docker-cli@remotedocker"
```

改めてコンテキストを確認すると、「remote」が追加されていることがわかります。

```console
> docker context ls
NAME              DESCRIPTION                               DOCKER ENDPOINT                             ERROR
desktop-linux *   Docker Desktop                            npipe:////./pipe/dockerDesktopLinuxEngine
remote                                                      ssh://docker-cli@remotedocker
```

以降、クライアント側で `docker` コマンドを使う際に `--context remote` を指定することで、サーバ側の docker を操作することができます。まずは動作確認もかねて `docker info` を使用します。

```console
> docker --context remote info
Client:
 Version:    27.2.0
 Context:    remote
 Debug Mode: false
 （中略）

Server:
 Containers: 0
 （中略）
 Operating System: AlmaLinux 9.4 (Seafoam Ocelot)
 OSType: linux
 （略）
```

「Server:」の情報を見ると、サーバ側の docker の情報になっていることがわかります。

:::note warn
`docker ... info` 実行後に入力を要求される場合や認証エラーになる場合は次の点を確認してください。

- ユーザ `docker-cli` が SSH でログインできるようになっている必要があります。また、クライアント側が持つ秘密鍵でログインできるよう、公開鍵が `docker-cli` に登録されている必要があります
- クライアント側の `~/.ssh/config` で秘密鍵のパスを設定していない場合、`~/.ssh/id_rsa` が使われるかパスワード認証が試みられます (agent を活用すれば回避可能)
- 秘密鍵にパスフレーズを指定している場合、パスフレーズの入力を要求されます (agent を活用すれば回避可能)
:::

### 2-2. (任意) デフォルトでサーバ側の docker を使用するようにする。

現在は `--context remote` を指定したときのみ上で作成したコンテキストが使用されサーバ側の docker につながりますが、`--context` を使わない場合はデフォルトのコンテキスト（今回の例では Docker Desktop）が使用されます。

`--context` を使わない場合に今回作成したコンテキストを使用してほしい場合は、今回作成したコンテキストをデフォルトに設定します。

まずは現在のデフォルトを確認します。

```console
> docker context ls
NAME              DESCRIPTION                               DOCKER ENDPOINT                             ERROR
desktop-linux *   Docker Desktop                            npipe:////./pipe/dockerDesktopLinuxEngine
remote                                                      ssh://docker-cli@remotedocker
```

アスタリスク (`*`) が付いている「desktop-linux」が現在のデフォルトです。

次のコマンドを実行することで、デフォルトを remote へ変更します。

```console
> docker context use remote
```

もう一度デフォルトを確認します。

```console
> docker context ls
NAME            DESCRIPTION                               DOCKER ENDPOINT                             ERROR
desktop-linux   Docker Desktop                            npipe:////./pipe/dockerDesktopLinuxEngine
remote *                                                  ssh://docker-cli@remotedocker
```

「remote」にアスタリスクが付いていれば、「remote」がデフォルトになっています。試しに、`--context` 無しで `docker info` コマンドを使用してみましょう。以下のように、コンテキストを指定しなくてもサーバ側の情報が表示されるはずです。

```console
> docker info
Client:
 Version:    27.2.0
 Context:    remote
 Debug Mode: false
 （中略）

Server:
 Containers: 0
 （中略）
 Operating System: AlmaLinux 9.4 (Seafoam Ocelot)
 OSType: linux
 （略）
```

## 3. 動作確認

クライアント側からサーバ側の docker を使用してみます。

:::note info
以降の例ではコンテキストのデフォルト設定を変えていないことを前提として `--context` オプションを使用しています。今回作成したコンテキストをデフォルトで使用する設定にしている場合、 `--context remote` は不要です。
:::

```console
> docker --context remote ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
> docker --context remote run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
e6590344b1a5: Pull complete
Digest: sha256:dd01f97f252193ae3210da231b1dca0cffab4aadb3566692d6730bf93f123a48
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
（略）

> docker --context remote ps -a
CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS                      PORTS     NAMES
5023eca1891b   hello-world   "/hello"   34 seconds ago   Exited (0) 31 seconds ago             pedantic_bhabha
```