2025/05/11 Updated by

Docker Image を自作する (3)

ubuntu 24.04LTS + 新規ユーザ + sshd + httpd


[Up] Japanese English
このページ内での表記:
「ホストOSの対話環境」は背景色を黄色(lightyellow)で表す。
「Conainer 内の root 権限の対話環境」は背景色を水色(azure)であらわす。
「Conainer 内の一般ユーザ権限の対話環境」は背景色を赤色(#ffeeee)であらわす。
「他のPCの対話環境」は紫色(#eeeeff)で表す。

sshd, httpd が自動起動する ubuntu24.04LTS の docker Image を生成する

方針

作成手順

  1. 作業用フォルダを作成する
  2.   $ mkdir -p ~/doc/docker/ubuntu24_sshd_httpd
      $ cd ~/doc/docker/ubuntu24_ssd_httpd
    
  3. 作業用フォルダの中に Dockerfile を作成する。
  4. 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 \
        apache2 \
        libapache2-mod-php \
        php-fpm \
        net-tools iputils-tracepath traceroute iputils-ping curl iproute2 \
        && 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
    
    
    # Apache 設定: ServerName エラー防止
    
    RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf
    
    # PHP 設定
    RUN sed -i 's/^;date\.timezone =.*/date\.timezone = "Asia\/Tokyo"/' /etc/php/8.3/apache2/php.ini
    
    # PHP-FPM によるPHPの高速化
    RUN sed -i \
        '/<\/VirtualHost>/i <FilesMatch "\\.php$">\n  SetHandler "proxy:unix:/var/run/php/php8.3-fpm.sock|fcgi://localhost/"\n</FilesMatch>' \
        /etc/apache2/sites-available/default-ssl.conf
    
    RUN a2enmod proxy_fcgi setenvif
    RUN a2enconf php8.3-fpm
    
    
    # supervisord の設定ファイルを設置する (Daemon 起動用)
    
    RUN mkdir -p /var/log/supervisor
    COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
    
    
    # ポート開放
    
    EXPOSE 22 80
    
    
    # Copy Shell Script "entrypoint.sh"
    
    COPY entrypoint.sh /entrypoint.sh
    RUN chmod +x /entrypoint.sh
    
    ENTRYPOINT ["/entrypoint.sh"]
    
    CMD []
    
  5. 作業用フォルダの中に entrypoint.sh を作成する
  6. 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
    	adduser ${UNAME} sudo
        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
    
  7. 作業用フォルダの中に supervisord.conf を作成する
  8. supervisord.conf
    # supervisord の設定ファイル
    
    [supervisord]
    nodaemon=true
    
    
    [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
    
    
    [program:php-fpm]
    command=/usr/sbin/php-fpm8.3 -F
    autostart=true
    autorestart=true
    stdout_logfile=/var/log/php-fpm.log
    stderr_logfile=/var/log/php-fpm.err
    
    
    [program:apache2]
    command=/usr/sbin/apachectl -D FOREGROUND
    autostart=true
    autorestart=true
    stopasgroup=true
    killasgroup=true
    stdout_logfile=/var/log/apache2_stdout.log
    stderr_logfile=/var/log/apache2_stderr.log
    
  9. Image を build する。
  10.   $ docker build -t ubuntu24_sshd_httpd .
      ...
    成功
    
  11. 生成した Image を確認する
  12. $ docker image ls
    REPOSITORY            TAG       IMAGE ID       CREATED         SIZE
    ubuntu24_sshd_httpd   latest    534506433e64   7 minutes ago   316MB
    ...
    
  13. (注意) 上で用意した supervisod.conf は、Container の /etc/supervisor/conf.d/supervisord.conf というパスにコピーしている。 supervisord を起動するときに設定ファイルとして指定しているのは、標準でインストールされる /etc/supervisor/supervisord.conf である。このファイルには /etc/supervisor/conf.d/*.conf をインクルードするように記述されている。
  14. [参考] 標準の /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       ← 誰でもファイルを作成できるが、作成した本人にしか消去できないモードに設定する
$ ls -ld /home/docker                ← ディレクトリのsticky bit が on になっていることを確認する。
drwxrwxrwt 3 root root 4096  4月 26 15:47 /home/docker

Docker Contaner を生成する (1)

Image ubuntu24_sshd_httpd を用いて、 新しい Container ubuntu24-httpd を生成する。

  1. image から container を生成して起動する。 下の実行例はユーザ名を www とした場合である。
  2.   $ docker run --name ubuntu24-httpd --restart always \
        -e UNAME=www \
        -p 11022:22 -p 11080:80 -p 11443:443 \
        -v /home/docker/httpd:/mnt/hostos \
        -it ubuntu24_sshd_httpd
    
    起動オプション
  3. Container を起動した対話環境が、そのままContainer 内で動作する bash との対話環境になる。root権限でloginした状態である。
  4. First run. Setting up ...            ← 生成された Container 内で entrypoint.sh が実行される
    Creating group www with GID=3000
    Creating user www with UID=3000, GID=3000
    info: Adding user `www' to group `sudo' ...
    ownership of '/home/www' retained as www:www
    No command provided. Starting bash ...
    2025-05-12 12:23:43,794 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-12 12:23:43,795 INFO supervisord started with pid 40
    2025-05-12 12:23:44,799 INFO spawned: 'apache2' with pid 43
    2025-05-12 12:23:44,801 INFO spawned: 'php-fpm' with pid 44
    2025-05-12 12:23:44,802 INFO spawned: 'sshd' with pid 45
    2025-05-12 12:23:45,822 INFO success: apache2 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
    2025-05-12 12:23:45,823 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
    2025-05-12 12:23:45,823 INFO success: sshd entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
    #                ← Container 内の対話環境 (root 権限の bash) が動く
    
  5. (Container 内の root 権限で) ユーザ名を調べる。
  6. # whoami
    root
    
  7. (Container 内の root 権限で) カレントディレクトリを調べる。
  8. # pwd
    /
    
  9. (Container 内の root 権限で) ホストOSのディレクトリをマウントしているディレクトリの様子を調べる。
  10. # ls -ld /mnt/hostos
    drwxr-xr-x 2 root root 4096 May 12 12:04 /mnt/hostos
    
  11. (Container 内の root 権限で) 新規ユーザ のホームディレクトリを調べる。
  12. # ls -ld /home/www
    drwxr-x--- 2 www www 4096 May 12 12:23 /home/www
    # ls -la /home/www
    total 20
    drwxr-x--- 2 www  www  4096 May 12 12:23 .
    drwxr-xr-x 1 root root 4096 May 12 12:23 ..
    -rw-r--r-- 1 www  www   220 Mar 31  2024 .bash_logout
    -rw-r--r-- 1 www  www  3771 Mar 31  2024 .bashrc
    -rw-r--r-- 1 www  www   807 Mar 31  2024 .profile
    
  13. キーボード操作 ('Control-P' と 'Control-Q' を連続してタイプする)により、ホストOSの対話環境に抜ける。 Container の対話環境は動作したままであるが、現在の端末からは切り離される。
  14. # ^p ^q ← Container内の対話環境で Control-P + Control-Q
    $ ← ホストOSの対話環境に戻る
  15. (ホストOSで) Container からマウントされているディレクトリの状況を調べる。
  16. $ ls -ld /home/docker
    drwxrwxrwt 6 root root 4096  5月 12 21:04 /home/docker
    # ls -la /home/docker
    合計 24
    drwxrwxrwt 6 root root 4096  5月 12 21:04 .
    drwxr-xr-x 4 root root 4096  5月  6 17:57 ..
    drwxr-xr-x 2 root root 4096  5月  6 18:29 guest
    drwxr-xr-x 2 root root 4096  5月 12 21:04 httpd
    drwxr-xr-x 2 root root 4096  5月  7 15:37 nitta
    drwxr-xr-x 2 root root 4096  5月 11 18:32 sshd
    $ ls -l /home/docker
    合計 16
    drwxr-xr-x 2 root root 4096  5月  6 18:29 guest
    drwxr-xr-x 2 root root 4096  5月 12 21:04 httpd
    drwxr-xr-x 2 root root 4096  5月  7 15:37 nitta
    drwxr-xr-x 2 root root 4096  5月 11 18:32 sshd
    
  17. (ホストOSで) docker の動作中の Container の一覧を見る。
  18. $ docker container ls
    CONTAINER ID   IMAGE                 COMMAND            CREATED  STATUS  PORTS                     NAMES
    145304f90056   ubuntu24_sshd_httpd   "/entrypoint.sh"   ...              0.0.0.0:11022->22/tcp,    ubuntu24-httpd
    									 0.0.0.0:11080->80/tcp,
    								         0.0.0.0:11443->443/tcp,
    ...
    
  19. ホストOSの対話環境を、Container 内の対話環境に再び接続する。
  20. $ docker attach ubuntu24-httpd ← docker attach コマンドで動作中のContainerに接続する
    # ← Container内の対話環境と再びつながった
  21. (Container 内の root 権限で) www ユーザに login する。
  22. # login wwwwww ユーザにログインする Password: ← パスワードを入力する。エコーバックされない。
    Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.11.0-25-generic x86_64) ... To run a command as administrator (user "root"), use "sudo ". See "man sudo_root" for details. www $
  23. (Container 内の www 権限で) パスワードを変更する。
  24. www $ passwd
    Changing password for guest.
    Current password: パスワード ← エコーバックされない
    New password:  新しいパスワード ← エコーバックされない
    Retype new password:  新しパスワード ← エコーバックされない
    passwd: password updated successfully
    
  25. Container 内の www ユーザ権限の対話環境を終了 Container 内の root 権限の対話環境に戻る。
  26. $ exit logout
    $
  27. Container 内の対話環境で Control-P + Control+Q をタイプすると、ゲストOSの対話環境は動作したままだが、手元の端末はホストOS の対話環境に戻る。
  28. # ^P ^Q read escape sequence
    $
  29. ssh を使ってネットワーク経由で Container の(新しい)対話環境にアクセスする。
  30. $ ssh -p 11022 www@localhost The authenticity of host '[localhost]:11022 ([127.0.0.1]:11022)' can't be established. ED25519 key fingerprint is SHA256:qFfoWarJPGj1PdGzxmoI32TAs06byIOBrrewHN/5GCE. This key is not known by any other names. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes Warning: Permanently added '[localhost]:11022' (ED25519) to the list of known hosts. www@localhost's password: www のパスワードを入力する。エコーバックされない。
    Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.11.0-25-generic x86_64) ← Container 内の www 権限の対話環境にネットワーク経由でアクセスする * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/pro This system has been minimized by removing packages and content that are not required on a system that users do not log into. To restore this content, you can run the 'unminimize' command. To run a command as administrator (user "root"), use "sudo ". See "man sudo_root" for details. www $
  31. (Container 内の www 権限の対話環境で) ユーザ名を確認する。
  32. www $ whoami
    www
    
  33. (Container 内の www 権限の対話環境で) ホームディレクトリを確認する。
  34. www $ pwd
    /home/www
    
  35. (Container 内の www 権限の対話環境で) ホームディレクトリのファイルを確認する。
  36. www $ ls -a
    .  ..  .bash_history  .bash_logout  .bashrc  .cache  .profile
    
  37. (Container 内の www 権限の対話環境で) 対話環境を終了する。
  38. www $ exit ← Container の www 権限の対話環境を終了する logout Connection to localhost closed.
    $ &arr; ホストOS の対話環境に戻る
  39. (ホスト OS の対話環境で) ホスト OS のファイアウォールの状態を確認する。
  40. $ sudo ufw status
    状態: アクティブ
    
    To                         Action      From
    --                         ------      ----
    80                         ALLOW       Anywhere
    22                         ALLOW       Anywhere
    443                        ALLOW       Anywhere
    3389                       ALLOW       Anywhere
    10022                      ALLOW       Anywhere
    
  41. (ホスト OS の対話環境で) Container にポートフォワーディングする 11022 番, 11080 番, 11443 番 ポートを開ける。
  42. (ホスト OS の対話環境で) ファイアウォールの状態を確認する。 外部から特定のポートへのアクセスが追加された。
  43. [SSH] 他のPCから、「ホストOSのIPアドレス」とポートフォワーディングされるポート番号を指定してssh アクセスする。 ホストOSの 11022 番ポートにアクセスすると、Container の 22 番ポートにポートフォワーディングされる。
  44. $ ssh -p 11022 www@192.168.12.3 ← ホストOSのIPアドレスと、ポートフォワーディングされるポート番号 www@192.168.12.3's password:
    Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.11.0-25-generic x86_64) ← Container の www 権限の対話環境が始まる * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/pro This system has been minimized by removing packages and content that are not required on a system that users do not log into. To restore this content, you can run the 'unminimize' command. Last login: Mon May 12 12:28:50 2025 from 172.17.0.1 To run a command as administrator (user "root"), use "sudo ". See "man sudo_root" for details. $ whoami www $ pwd /home/www $ ls -a . .. .bash_history .bash_logout .bashrc .cache .profile $ exit ← Container の www 権限の対話環境を終了する logout Connection to 192.168.12.3 closed.
    $ ← 他の PC の対話環境に戻る
  45. [WWW] 他のPC からブラウザを用いて、「ホストOSのIPアドレス」とポートフォワーディングされるポート番号を指定して WWW アクセスする。
  46. URL: http://ホストOSのIPアドレス:ポート番号/
    URL: http://192.168.12.3:11080/


  47. apache2 の再起動には supervisorctl を用いる。
  48. $ supervisorctl restart apache2   
    

docker の内部ネットワークに関する注意

上記のように起動したcontainer 上の www サーバでは、アクセスしてくるクライアントのipアドレスを用いたアクセス制限がうまく動作しない。 その原因は、

「docker ホストos (172.17.0.1) がdocker内部ネットワーク(172.17.0.0/16)に対して napt をかけていて、 外部からのアクセスがすべて 172.17.0.1 からに見える」
からである。

docker 内部ネットワークの調査

  1. ホストosとは異なるマシンでブラウザを立ち上げて、container ubuntu24-sshd-httpd 上のwwwサーバにアクセスする。
  2. url は http://ホストosのipアドレス:11080/
  3. container ubuntu24-sshd-httpd に ssh アクセスする。
  4. $ ssh -p 21022 www@localhost
    www@localhost's password: パスワード ← エコーバックされない
    (ゲスト os のシェルが起動する)
    welcome to ubuntu 24.04.2 lts (gnu/linux 6.10.14-linuxkit x86_64)
    ...
    $
    
  5. wwwサーバのlogを表示する。← すべてのwwwアクセスが 172.17.0.1 からになっていることがわかる
  6. $ sudo tail /var/log/apache2/access.log
    ...
    172.17.0.1 - - [04/may/2025:05:10:49 +0000] "get /work2/ http/1.1" 200 21202 "http://ホストosのipアドレス:11080/" ...
    172.17.0.1 - - [04/may/2025:05:10:53 +0000] "get /work3/ http/1.1" 200 21202 "http://ホストosのipアドレス:11080/" ...
    
  7. ネットワークコマンドをインストールする。 ← 今回は Dockerfile 内の RUN 文で install 済み。
  8. まず、aptのデータベースを更新する。
    $ sudo apt update
    
    ifconfig, netstat, arp をインストールする
    $ sudo apt install -y net-tools
    
    traceroute をインストールする
    $ sudo apt install -y iputils-tracepath traceroute
    
    ping をインストールする
    $ sudo apt install -y iputils-ping
    
    curl をインストールする
    $ sudo apt install -y curl
    
    ip をインストールする
    $ sudo apt install -y iproute2
    
  9. netstat コマンドを用いて、ルーティング情報を調べる。 → container が接続しているネットワークは 172.17.0.0/16で、 デフォルトのルーティング先が 172.17.0.1 であることがわかる
  10. $ netstat -nr
    kernel ip routing table
    destination     gateway         genmask         flags   mss window  irtt iface
    0.0.0.0         172.17.0.1      0.0.0.0         ug        0 0          0 eth0
    172.17.0.0      0.0.0.0         255.255.0.0     u         0 0          0 eth0
    
  11. ifconfig でcontainer のipアドレスを調べる。 → 172.17.0.2 であることがわかる。
  12. $ ifconfig
    eth0: flags=4163  mtu 1500
            inet 172.17.0.2  netmask 255.255.0.0  broadcast 172.17.255.255
            ether xx:xx:xx:xx:xx:xx  txqueuelen 0  (ethernet)
            rx packets 57700  bytes 10953734 (10.9 mb)
            rx errors 0  dropped 0  overruns 0  frame 0
            tx packets 56874  bytes 6131126 (6.1 mb)
            tx errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    lo: flags=73  mtu 65536
            inet 127.0.0.1  netmask 255.0.0.0
            inet6 ::1  prefixlen 128  scopeid 0x10
            loop  txqueuelen 1000  (local loopback)
            rx packets 0  bytes 0 (0.0 b)
            rx errors 0  dropped 0  overruns 0  frame 0
            tx packets 0  bytes 0 (0.0 b)
            tx errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    

対策

対策は3通りあるようだ。

docker network を生成する

network.php

「アクセスしてきたクライアントの正しいipアドレスが container 上の httpdサーバ (apache2) に伝わる」ように macvlan を使って「Container に物理 NIC と同じネットワークの独立した IP アドレスを与える」方法を採る。

前提条件と環境

  1. ホストOSの接続しているネットワークを調べる。
  2. $ netstat -nr
    カーネルIP経路テーブル
    受信先サイト    ゲートウェイ    ネットマスク   フラグ   MSS Window  irtt インタフェース
    0.0.0.0         192.168.12.1    0.0.0.0         UG        0 0          0 eno1
    172.17.0.0      0.0.0.0         255.255.0.0     U         0 0          0 docker0
    192.168.12.0    0.0.0.0         255.255.255.0   U         0 0          0 eno1
    
  3. ホストOSの IP アドレスを調べる。
  4. $ ifconfig 
    	...
    eno1: flags=4163  mtu 1500
            inet 192.168.12.3  netmask 255.255.255.0  broadcast 192.168.12.255
            inet6 2409:11:3920:6400:5a47:caff:fe71:3b7d  prefixlen 64  scopeid 0x0
            inet6 2409:11:3920:6400:4c1a:ff8c:eab1:41c9  prefixlen 64  scopeid 0x0
            inet6 fe80::5a47:caff:fe71:3b7d  prefixlen 64  scopeid 0x20
            ether 58:47:ca:71:3b:7d  txqueuelen 1000  (イーサネット)
    ...
    
  5. macvlan ネットワークを作成する。
  6. $ docker network create -d macvlan \
        --subnet=192.168.12.0/24 \
        --gateway=192.168.12.1 \
        -o parent=eno1 \
        --ip-range=192.168.12.192/28 \
        macvlan_net
    
    
  7. docker のネットワーク一覧を表示する。macvlan_net が作成されていることがわかる。
  8. $ docker network ls
    NETWORK ID     NAME          DRIVER    SCOPE
    ebbd998b2086   bridge        bridge    local
    17420af9f271   host          host      local
    557533733a33   macvlan_net   macvlan   local
    a3538f29efc6   none          null      local
    
    $ docker network ls --no-trunc
    NETWORK ID                                                         NAME          DRIVER    SCOPE
    ebbd998b20868aea17c1e9f3cd85edb3c7c0ce9181edfe9b308284604275e136   bridge        bridge    local
    17420af9f27199ef5081c56e85910d913c73ae8f3885e48e4ed0b09a06d48016   host          host      local
    557533733a33e84ca9eb665736f6a273414778f30a3e744411596008728b0b2b   macvlan_net   macvlan   local
    a3538f29efc60166d3f639d42894eff9f902649036619190011c3a66b262a06a   none          null      local
    

Docker Contaner を生成する (2)

Image ubuntu24_sshd_httpd を用いて、 macvlan_net ネットワークに接続する、 新しい Container ubuntu24-sshd-httpd2 を生成する。

上記の「Docker Contaner を生成する (1)」に対して、以下の変更を加える。

Container を作成+実行する

  1. image から container を生成して起動する。 下の実行例はユーザ名を www とした場合である。
  2.   $ docker run --name ubuntu24-sshd-httpd-vlan --restart always \
        -e UNAME=www -e UID=2000 -e GID=2000 \
        --network macvlan_net \
        --ip 192.168.12.193 \
        --cap-add=NET_ADMIN \
        -v /home/docker/httpd:/mnt/hostos \
        -it ubuntu24_sshd_httpd
    
    起動オプション
  3. Container を起動した対話環境が、そのままContainer 内で動作する bash との対話環境になる。root権限でloginした状態である。
  4. First run. Setting up ...
    Creating group www with GID=2000
    Creating user www with UID=2000, GID=2000
    info: Adding user `www' to group `sudo' ...
    ownership of '/home/www' retained as www:www
    No command provided. Starting bash ...
    root@961393dcc800:/# 2025-05-18 07:08:19,525 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-18 07:08:19,527 INFO supervisord started with pid 40
    2025-05-18 07:08:20,529 INFO spawned: 'apache2' with pid 43
    2025-05-18 07:08:20,531 INFO spawned: 'php-fpm' with pid 44
    2025-05-18 07:08:20,533 INFO spawned: 'sshd' with pid 45
    2025-05-18 07:08:21,568 INFO success: apache2 entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
    2025-05-18 07:08:21,569 INFO success: php-fpm entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
    2025-05-18 07:08:21,569 INFO success: sshd entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
    #                ← Container 内の対話環境 (root 権限の bash) が動く
    
  5. ネットワークコマンドはインストール済みである。もしも、インストールされていない場合は以下の手順でインストールする。
  6. まず、aptのデータベースを更新する。
    #  apt update
    
    ifconfig, netstat, arp をインストールする
    # apt install -y net-tools
    
    traceroute をインストールする
    $ apt install -y iputils-tracepath traceroute
    
    ping をインストールする
    $ sudo apt install -y iputils-ping
    
    curl をインストールする
    $ sudo apt install -y curl
    
    ip をインストールする
    $ sudo apt install -y iproute2
    
  7. netstat コマンドを用いて、ルーティング情報を調べる。 → Container が接続しているネットワークは 192.168.12.0/24で、 デフォルトのルーティング先が 192.168.12.1 であることがわかる
  8. $ netstat -nr
    Kernel IP routing table
    Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
    0.0.0.0         192.168.12.1    0.0.0.0         UG        0 0          0 eth0
    192.168.12.0    0.0.0.0         255.255.255.0   U         0 0          0 eth0
    
  9. ifconfig でContainer のIPアドレスを調べる。 → 192.168.12.193 であることがわかる。
  10. $ ifconfig
    eth0: flags=4163  mtu 1500
            inet 192.168.12.193  netmask 255.255.255.0  broadcast 192.168.12.255
            ether 8a:9e:8a:00:aa:16  txqueuelen 0  (Ethernet)
            RX packets 5434  bytes 30400112 (30.4 MB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 4498  bytes 300984 (300.9 KB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    lo: flags=73  mtu 65536
            inet 127.0.0.1  netmask 255.0.0.0
            inet6 ::1  prefixlen 128  scopeid 0x10
            loop  txqueuelen 1000  (Local Loopback)
            RX packets 8  bytes 1058 (1.0 KB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 8  bytes 1058 (1.0 KB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
  11. Container では firewall は動作していない。現在の Image 元にした ubuntu:24.04 では ufw や iptavbles がインストールされていないため。
  12. # iptables -L
    bash: iptables: command not found
    # ufw status
    bash: ufw: command not found
    
  13. 手動で firewall を設定する。
  14. ufw をインストールする。
    # apt update && apt install -y ufw
    
    ufw を有効化する
    # ufw enable
    Status: active
    
    # ufw allow from 0.0.0.0/0 to any port 22 proto tcp
    Rule added
    # ufw allow from 0.0.0.0/0 to any port 80 proto tcp
    Rule added
    # ufw allow from 0.0.0.0/0 to any port 443 proto tcp
    Rule added
    
    外部からのアクセスはデフォルトで禁止にする。
    # ufw default deny incoming
    
    ファイアウォールの設定状況を見る
    # ufw status
    Status: active
    To                         Action      From
    --                         ------      ----
    22/tcp                     ALLOW       Anywhere
    80/tcp                     ALLOW       Anywhere
    443/tcp                    ALLOW       Anywhere
    
  15. ネットワーク上の他のマシンから、ssh接続できることを確認する。
  16. sshで
    $ ssh www@192.168.12.193
    
    [注意] パスワードを迅速に変更しておくこと。
  17. ネットワーク上の他のマシンから httpd 接続できることを確認する。
  18. ブラウザで url: http://192.168.12.193/

macvlan に関する注意

  1. -cap-add=NET_ADMIN オプションを指定せずに起動したContainer 内の root 権限で ufw を実行すると、エラーとなる。
  2. $ sudo ufw status
    ...
    WARN: initcaps
    [Errno 2] iptables v1.8.10 (nf_tables): Could not fetch rule set generation id: Permission denied (you must be root)
    
    Rules updated
    

    原因

    Docker は通常、CAP_NET_ADMIN などの 特権ケーパビリティを制限している。 そのため、Container で ufw を使う場合、通常の root 権限では不十分なことが多い。

    対策

    方法1: --cap-add=NET_ADMIN を付けて起動する
    docker run \
      --cap-add=NET_ADMIN \
      --network macvlan_net \
      --ip 192.168.1.100 \
      -it ubuntu:24.04
      
    方法2: コンテナを「特権モード」で起動する(セキュリティ上のリスクがあるため、推奨されない)
    docker run \
      --privileged \
      --network macvlan_net \
      --cap-add=NET_ADMIN \
      --ip 192.168.1.100 \
      -it ubuntu:24.04
    
  3. (参考) Dockerfile に firewall 設定を含む手順
  4. Dockerfileに追加
    FROM ubuntu:24.04
    RUN apt update && apt install -y ufw
    RUN ufw allow 80 && ufw enable
    
    (注意) "ufw enable" はインタラクティブな挙動をするため、適切な処理が必要となる。

代替案(推奨)

ufw を使わず Apache2 などのアプリ側でバインドポートを限定する。
例:Apache2 を 80 のみで Listen