2025/05/04 Updated by 
Docker Image を自作する (2)
ubuntu 24.04LTS + 新規ユーザ + sshd
[Up]
 

このページ内での表記:
「ホストOSの対話環境」は背景色を黄色(lightyellow)で表す。
「Conainer 内の root 権限の対話環境」は背景色を水色(azure)であらわす。
「Conainer 内の一般ユーザ権限の対話環境」は背景色を赤色(#ffeeee)であらわす。
「他のPCの対話環境」は紫色(#eeeeff)で表す。
sshd が自動起動する ubuntu24.04LTS の docker Image を生成する
方針
- ゲストOS は Ubuntu 24.04LTS 
- sshd を自動起動する。
- Container の初回起動時に、SSH のポート番号を設定する。(SSHD_PORT 変数, デフォルト値: 22) 
- Container の初回起動時に、新規ユーザを作成する。(デフォルト値: geust)
- Container の初回起動時にコマンドが与えられた場合は、フォアグラウンドで実行する。
- 生成する Docker Image 名は ubuntu24_sshd
作成手順
- 作業用フォルダを作成する
  $ mkdir -p ~/doc/docker/ubuntu24_sshd   $ cd ~/doc/docker/ubuntu24_sshd
  $ cd ~/doc/docker/ubuntu24_sshd   
- 作業用フォルダの中に Dockerfile を作成する。
- Dockerfile中の パスワード の部分は、推測されにくい文字列に必ず変更すること。
- Dockerfile 中の Run 命令は docker image を build する時に実行されるので、変数を使っていても build時の値で固定される。
- Container の初回起動時に変数の値を変更したいコマンド(たとえば、SSHD_PORT )は、ENTRYPOINT で呼び出すシェルスクリプトの中で実行する。
- OpenSSH サーバをインストールする。
- supervisor サーバをインストールする。これはContainer を起動するたびに他のサーバを自動起動する役目を担う。
| Dockerfile | 
| # ゲストOS: Ubuntu 24.04 LTS
FROM ubuntu:24.04
# Change Your Own UNAME, UID, GID, PASS
ENV UNAME=guest
ENV UID=3000
ENV GID=3000
ENV PASS=パスワード
ENV SSHD_PORT=22
# 必要なパッケージのインストール
RUN apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get install -y \
    sudo \
    bash \
    openssh-server \
    supervisor \
    && rm -rf /var/lib/apt/lists/*
# SSH 設定: パスワード認証を有効化
RUN sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config && \
    sed -i "s/^#Port.*/Port ${SSHD_PORT}/" /etc/ssh/sshd_config && \
    mkdir /var/run/sshd
# supervisord の設定ファイルを設置する (Daemon 起動用)
RUN mkdir -p /var/log/supervisor
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# ポート開放
EXPOSE 22
# Copy Shell Script "entrypoint.sh"
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD []
 | 
- 作業用フォルダの中に entrypoint.sh を作成する
- Contaienr の初回起動時に、SSHサーバの待ち受けポート番号を設定する。
- Container が起動されるたびに supervisor デーモンを起動する。SSHサーバの起動は supervisor が行う。
| entrypoint.sh | 
| #!/bin/bash
set -e
if [ ! -f /var/app/.initialized ]; then
    ######## First Time ########
    echo "First run. Setting up ..."
    mkdir -p /var/app
    touch /var/app/.initialized
    # ユーザーが存在しない場合のみ作成する
    if id "${UNAME}" &>/dev/null; then
        echo "User ${UNAME} already exists. Skipping creation."
    else
        # 同名グループが無ければ作成する
        if ! getent group "${UNAME}" &>/dev/null; then
            echo "Creating group ${UNAME} with GID=${GID}"
            groupadd -g ${GID} ${UNAME}
        else
            echo "Group ${UNAME} already exists. Skipping group creation."
        fi
    
        echo "Creating user ${UNAME} with UID=${UID}, GID=${GID}"
        useradd -m -u ${UID} -g ${GID} -s /bin/bash ${UNAME}
        echo "${UNAME}:${PASS}" | chpasswd
        usermod -aG sudo ${UNAME}
    fi
    # ホームディレクトリの Owner が root:root になることがあるので明示的に変更する。
    chown -v ${UNAME}:${UNAME}  /home/${UNAME}
    # SSHD のポート番号を変更する
    sed -i "s/^Port.*/Port ${SSHD_PORT}/" /etc/ssh/sshd_config
    
else
    ######## Second Time or Later ########
    
    echo "Starting for the second time or later ..."
fi
# supervisord start (background)
/usr/bin/supervisord -c /etc/supervisor/supervisord.conf &
# Execute Commands in CMD
if [ "$#" -gt 0 ]; then
    exec "$@"
else
    echo "No command provided. Starting bash ..."
    exec bash
fi
 | 
- 作業用フォルダの中に supervisord.conf を作成する
- supervisord の設定ファイルは /etc/supervisor/supervisord.conf にあり、追加の設定は /etc/supervisor/conf.d/*.conf で
記述するように設定する。
- sshd のログをとるために sshd に -e オプションをつけて起動して、sshdプロセスの標準出力にログを出力させる。
- 標準出力と標準エラー出力をそれぞれ /var/log/sshd_std{out,err}.log というファイルに記録する。
| supervisord.conf | 
| # supervisord の設定ファイル
[supervisord]
nodaemon=true
# sshd を起動する
[program:sshd]
command=/usr/sbin/sshd -D -e
autostart=true
autorestart=true
stdout_logfile=/var/log/sshd_stdout.log
stderr_logfile=/var/log/sshd_stderr.log
 | 
-  Image を build する。
  $ docker build -t ubuntu24_sshd .   ...
成功
  ...
成功
- 生成した Image を確認する
$ docker image ls   REPOSITORY      TAG       IMAGE ID       CREATED         SIZE
ubuntu24_sshd   latest    23164575e4d2   8 seconds ago   222MB
...
REPOSITORY      TAG       IMAGE ID       CREATED         SIZE
ubuntu24_sshd   latest    23164575e4d2   8 seconds ago   222MB
...
- (注意) 上で用意した supervisod.conf は、Container の
/etc/supervisor/conf.d/supervisord.conf
というパスにコピーしている。
supervisord を起動するときに設定ファイルとして指定しているのは、標準でインストールされる
/etc/supervisor/supervisord.conf
である。このファイルには /etc/supervisor/conf.d/*.conf をインクルードするように記述されている。
| [参考] 標準の /etc/supervisor/supervisord.conf | 
| ; supervisor config file
[unix_http_server]
file=/var/run/supervisor.sock   ; (the path to the socket file)
chmod=0700                       ; sockef file mode (default 0700)
[supervisord]
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log)
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)
childlogdir=/var/log/supervisor            ; ('AUTO' child log dir, default $TEMP)
; the below section must remain in the config file for RPC
; (supervisorctl/web interface) to work, additional interfaces may be
; added by defining them in separate rpcinterface: sections
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
[supervisorctl]
serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL  for a unix socket
; The [include] section can just contain the "files" setting.  This
; setting can list multiple files (separated by whitespace or
; newlines).  It can also contain wildcards.  The filenames are
; interpreted as relative to this file.  Included files *cannot*
; include files themselves.
[include]
files = /etc/supervisor/conf.d/*.conf
 | 
Container 用の永続的なファイルシステムを作成する
コンテナに永続的なファイルシステムを提供するために、1777 のパーミッションでフォルダを作っておく。
skicky bit が on (1777) のフォルダには、
「誰でもファイルを作成できるが、作成した本人だけがファイルを変更したり消したりできる」
という特徴がある。
$ sudo mkdir -p /home/docker   ← ディレクトリを作成する
$ sudo chmod 1777 /home/docker
          ← ディレクトリを作成する
$ sudo chmod 1777 /home/docker   ← 誰でもファイルを作成できるが、作成した本人にしか消去できないモードに設定する
$ ls -ld /home/docker
        ← 誰でもファイルを作成できるが、作成した本人にしか消去できないモードに設定する
$ ls -ld /home/docker   ← ディレクトリのsticky bit が on になっていることを確認する。
drwxrwxrwt 3 root root 4096  4月 26 15:47 /home/docker
                 ← ディレクトリのsticky bit が on になっていることを確認する。
drwxrwxrwt 3 root root 4096  4月 26 15:47 /home/docker
Docker Contaner を生成する
Image ubuntu24_sshd 
のデフォルトのユーザ情報とSSHサーバ情報を用いて、
新しい Container
ubuntu24-sshd
を生成する。
- Image から Container を生成して起動する。ユーザ情報はデフォルト値 (guest) を利用する。
Container のファイルシステム内にホストOSのディレクトリをマウントする。
Container を起動するたびに、sshd サーバが起動される。
$ docker run --name ubuntu24-sshd --restart always \
    -p 10022:22 \
    -v /home/docker/sshd:/mnt/hostos \
    -it ubuntu24_sshd   
起動オプション
  
  - --name: 生成する Container の名前は ubuntu24-sshd
- --restart always: docker が起動すると、このコンテナも自動起動する。
- -p: ホストOSのポート番号 10022 へのアクセスを、Container のポート番号 22 にフォワーディングする。 
    | ポート番号 | 
|---|
    | ホストOS | ゲストOS | 
|---|
    | 10022 | 22 | 
    
  - -v: ホストOSの /home/docker/sshd が Container の /mnt/hostos としてマウントされる。 
    | マウントポイント | 
|---|
    | ホストOS | ゲストOS | 
|---|
    | /home/docker/ssh | /mnt/hostos | 
    
  - -it: 対話モード。ホストOSの端末をそのまま、Container 内の bash との対話環境として使う。
  
- 使用する Docker Image は ubuntu24_sshd
- Container を起動した対話環境が、そのまま Container 内で動作する bash との対話環境になる。root権限でloginした状態である。
First run. Setting up ...       ← 生成された Container 内で entrypoint.sh が実行される
Creating group guest with GID=3000
Creating user guest with UID=3000, GID=3000
ownership of '/home/guest' retained as guest:guest
No command provided. Starting bash ...
root@af401d3cdf85:/# 2025-05-11 09:32:40,710 CRIT Supervisor is running as root.  Privileges were not dropped because no user is specified in the config file.  \
If you intend to run as root, you can set user=root in the config file to avoid this message.
2025-05-11 09:32:40,711 INFO supervisord started with pid 38
2025-05-11 09:32:41,715 INFO spawned: 'sshd' with pid 41
2025-05-11 09:32:42,717 INFO success: sshd entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
#              ← Container 内の対話環境 (root権限の bash) が動く
- (重要) (Container 内で) 直ちに新規ユーザ guest のパスワードを変更する。
$ passwd guest  New password:                   ← 新しいパスワード を入力する。
Retype new password:            ← もう一度新しいパスワード を入力する。
passwd: password updated successfully
  
New password:                   ← 新しいパスワード を入力する。
Retype new password:            ← もう一度新しいパスワード を入力する。
passwd: password updated successfully
- (Container 内で) ホストOSのマウントポイントを調べる。
# ls -ld /mnt/hostos   drwxr-xr-x 2 root root 4096 May 11 09:32 /mnt/hostos
  
drwxr-xr-x 2 root root 4096 May 11 09:32 /mnt/hostos
- (Container 内で) 新規ユーザのホームディレクトリを調べる。
# ls -ld /home/guest   drwxr-x--- 2 guest guest 4096 May 11 09:32 /home/guest
# ls -la /home/guest
  
drwxr-x--- 2 guest guest 4096 May 11 09:32 /home/guest
# ls -la /home/guest   total 20
drwxr-x--- 2 guest guest 4096 May 11 09:32 .
drwxr-xr-x 1 root  root  4096 May 11 09:32 ..
-rw-r--r-- 1 guest guest  220 Mar 31  2024 .bash_logout
-rw-r--r-- 1 guest guest 3771 Mar 31  2024 .bashrc
-rw-r--r-- 1 guest guest  807 Mar 31  2024 .profile
  
total 20
drwxr-x--- 2 guest guest 4096 May 11 09:32 .
drwxr-xr-x 1 root  root  4096 May 11 09:32 ..
-rw-r--r-- 1 guest guest  220 Mar 31  2024 .bash_logout
-rw-r--r-- 1 guest guest 3771 Mar 31  2024 .bashrc
-rw-r--r-- 1 guest guest  807 Mar 31  2024 .profile
- (Container 内で) Control-P と Control-Q を順にタイプして、ホストOSの対話環境に戻る。
Container 内のシェルは動作したままとなる。
# ^p ^q                ← Container の対話環境を抜ける
$              ← ホストOS 内の対話環境に戻る
- (ホストOS上) Container からマウントされているホストOSのディレクトリを調べる。
$ ls -ld /home/docker/sshd   drwxr-xr-x 2 root root 4096  5月 11 18:32 /home/docker/sshd
 
drwxr-xr-x 2 root root 4096  5月 11 18:32 /home/docker/sshd
- (ホストOS上) docker 上の実行中の container の状態を調べる
$ docker container ls   CONTAINER ID   IMAGE           COMMAND            CREATED         STATUS         PORTS                                       NAMES
af401d3cdf85   ubuntu24-sshd   "/entrypoint.sh"   4 minutes ago   Up 4 minutes   0.0.0.0:10022->22/tcp, [::]:10022->22/tcp   ubuntu24-sshd
 
CONTAINER ID   IMAGE           COMMAND            CREATED         STATUS         PORTS                                       NAMES
af401d3cdf85   ubuntu24-sshd   "/entrypoint.sh"   4 minutes ago   Up 4 minutes   0.0.0.0:10022->22/tcp, [::]:10022->22/tcp   ubuntu24-sshd
- (ホストOS上) docker 上のすべての(停止中を含む) container の状態を調べる
$ docker container ls -a   CONTAINER ID   IMAGE           COMMAND            CREATED         STATUS         PORTS                                       NAMES
af401d3cdf85   ubuntu24-sshd   "/entrypoint.sh"   4 minutes ago   Up 4 minutes   0.0.0.0:10022->22/tcp, [::]:10022->22/tcp   ubuntu24-sshd
 
CONTAINER ID   IMAGE           COMMAND            CREATED         STATUS         PORTS                                       NAMES
af401d3cdf85   ubuntu24-sshd   "/entrypoint.sh"   4 minutes ago   Up 4 minutes   0.0.0.0:10022->22/tcp, [::]:10022->22/tcp   ubuntu24-sshd
- (ホストOS上) docker 上の Image の一覧を表示する。
- 
$ docker image ls   REPOSITORY      TAG       IMAGE ID       CREATED             SIZE
ubuntu24-sshd   latest    23164575e4d2   About an hour ago   222MB
ubuntu24-user   latest    7b64f0b8bea1   3 hours ago         81.4MB REPOSITORY      TAG       IMAGE ID       CREATED             SIZE
ubuntu24-sshd   latest    23164575e4d2   About an hour ago   222MB
ubuntu24-user   latest    7b64f0b8bea1   3 hours ago         81.4MB
 
Docker Host から ssh を用いてContainer 内の対話環境にアクセスする
- ホストOSから、Continer の guest ユーザのアカウントに ssh でアクセスする。
- localhost からのアクセスはファイアウォールの干渉を受けないので、
ファイアウォールが動作していてもアクセス可能である。
- Container 作成時の -p 10022:22 オプションの指定により、
ホストOSの 10022 番ポートへのアクセスは Container の 22 番ポートにポートフォワーディングされる。
$ 
ssh -p 10022 guest@localhost   ← ホストOSの 10022 番ポートに sshアクセスする
          ← ホストOSの 10022 番ポートに sshアクセスする
...
Are you sure you want to continue connecting (yes/no/[fingerprint])? 
yes   
 
...
guest@localhost's password: 
    ← パスワードを入力する。エコーバックされない。Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.11.0-25-generic x86_64)
...
$               ← Container 内の guest 権限の対話環境が開始する
- (Container 内の guest 権限で) ユーザ名を表示する。
$ whoami   guest
 
guest
- (Container 内の guest 権限で) ホームディレクトリを表示する。
$ pwd   /home/guest
 
/home/guest
- (Container 内の guest 権限で) ホームディレクトリにあるファイルの一覧を表示する。
$ ls -la   total 24
drwxr-x--- 3 guest guest 4096 May 11 09:35 .
drwxr-xr-x 1 root  root  4096 May 11 09:32 ..
-rw-r--r-- 1 guest guest  220 Mar 31  2024 .bash_logout
-rw-r--r-- 1 guest guest 3771 Mar 31  2024 .bashrc
drwx------ 2 guest guest 4096 May 11 09:35 .cache
-rw-r--r-- 1 guest guest  807 Mar 31  2024 .profile
 
total 24
drwxr-x--- 3 guest guest 4096 May 11 09:35 .
drwxr-xr-x 1 root  root  4096 May 11 09:32 ..
-rw-r--r-- 1 guest guest  220 Mar 31  2024 .bash_logout
-rw-r--r-- 1 guest guest 3771 Mar 31  2024 .bashrc
drwx------ 2 guest guest 4096 May 11 09:35 .cache
-rw-r--r-- 1 guest guest  807 Mar 31  2024 .profile
- (Container 内の guest 権限で) ssh 経由の対話環境を終了する。
guest@af401d3cdf85:~$ exit  

 
logout
Connection to localhost closed.
$  
他のPCからネットワーク経由で Container 内の対話環境にアクセスする
- (ホストOS上) 外部のPCからネットワーク経由で Container にアクセスするためには、ホストOSの 10022 番ポートを開けておく必要がある。
Docker の公式文書では、「docker のポートフォワーディングは ufw のフィルタリングよりも前に行わるために、ufw の影響を受けない」
と記述されている (2025年春時点) が、これは現時点では間違いのようだ。
Containerに外部からアクセスするためには、ホストOSのポートを開けておく必要がある。
Ubuntu 24.04LTS の場合: ufw を用いる
  
  - (ホストOS上) ファイアウォール ufw を有効化する。(既に有効化してあれば必要なし)
  $ sudo apt update   ← aptのデータベースを更新する
  $ sudo apt install -y ufw
                        ← aptのデータベースを更新する
  $ sudo apt install -y ufw   ← ufw をインストールする。
  $ sudo systemctl enable ufw
                ← ufw をインストールする。
  $ sudo systemctl enable ufw   ← ufw を有効化する
  $ sudo systemctl restart ufw
                ← ufw を有効化する
  $ sudo systemctl restart ufw   ← ufw を再起動する
                ← ufw を再起動する
  
  - (ホストOS上) ホストOSの 10022 番ポートを開放する。
  $ sudo ufw allow 10022   ← 10022 番ポートを開放する
  ルールを追加しました
  ルールを追加しました (v6)
                        ← 10022 番ポートを開放する
  ルールを追加しました
  ルールを追加しました (v6)
  
  - (ホストOS上)  ファイアウォールの状態を確認する。
  $ sudo ufw status 10022   ← 10022 番ポートを開放する
  ...
状態: アクティブ
To                         Action      From
--                         ------      ----
...
10022                      ALLOW       Anywhere
...
10022 (v6)                 ALLOW       Anywhere (v6)
  ...
                        ← 10022 番ポートを開放する
  ...
状態: アクティブ
To                         Action      From
--                         ------      ----
...
10022                      ALLOW       Anywhere
...
10022 (v6)                 ALLOW       Anywhere (v6)
  ...
  
- (ネットワーク上の他のPC) 他のマシンから、ホストOS上の Container に ssh 接続する。
以下は、ホストOSの IPアドレスが 192.168.12.3 の場合の、ssh アクセスの様子である。
(他のPCから)
$ 
ssh -p 10022 guest@192.168.12.3   
 
guest@192.168.12.3's password: 
    ← パスワードを入力する。エコーバックされない。
Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.11.0-25-generic x86_64)
...
guest $ 
whoami   
                 ← Container に 
guest 権限でアクセスできる
guest
guest $ 
exit   
 
logout
Connection to 192.168.12.3 closed.
$ 
 
Container が再起動すると sshd も自動起動されることを確認する
- (ホストOS上で) Container を停止する
$ docker container stop ubuntu24-sshd   
 
- (ホストOS上で) Container が停止されたことを確認する
$ docker container ls   CONTAINER ID   IMAGE           COMMAND            CREATED         STATUS         PORTS          NAMES
 
CONTAINER ID   IMAGE           COMMAND            CREATED         STATUS         PORTS          NAMES
- (ホストOS上で) 停止中の Container を起動する
$ docker start ubuntu24-sshd   
 
- (ホストOS上で) Container に ssh でアクセスして、sshd が自動的に起動していることを確認する。
$ 
ssh -p 10022 guest@localhost   ← ホストOSの 10022 番ポートに sshアクセスする
          ← ホストOSの 10022 番ポートに sshアクセスする
guest@localhost's password: 
    ← パスワードを入力する。エコーバックされない。Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.11.0-25-generic x86_64)
...
$               ← Container 内の guest 権限の対話環境が開始する
