• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

CENTOS上的网络安全工具十四搬到Docker上2?

武飞扬头像
lhyzws
帮助1

        既然说要搬到Docker上,那么肯定是要把咱日常习惯用的那些东西都往docker上堆一堆看的。我最先考虑的居然是SSH,乃至于到现在我都不知道我为什么第一个想到的是SSH——因为对虚拟机来说,首先考虑的当然是如何远程管理集群中的每个机器,这个自然是需要SSH的;但是对于docker来说,难道不是直接使用docker命令就可以了?为什么要SSH?

        本篇的内容,记录了诸如此类的,我在初入docker时的一系列奇思妙想,以及在这些奇思妙想引导下掉进的一个有一个大坑。不幸的是,没几个坑最终爬出来了;幸运的是,正是因为扑街得很惨,所以更容易体会“docker不是虚拟机,只是进程隔离的工具”这句话的涵义。有助于后面在使用docker时正确的认识并定位它。

        一、Systemd

        直接在docker里执行systemctl,一般只会得到如下反馈:        

  1.  
    [root@d47ccf7a7196 /]# systemctl
  2.  
    System has not been booted with systemd as init system (PID 1). Can't operate.
  3.  
    Failed to connect to bus: Host is down

        原因?就藏在docker的run命令里面——为什么docker run命令后面会跟一个/bin/bash之类的默认执行程序地址?或者在dockerfile文件里会使用[CMD]或者[ENTRYPOINT]来指示docker执行时默认执行程序?——从进程隔离的角度来理解,docker就是干这个事的,给你一个能够执行某个进程的最小操作系统环境而已。所以,如果没有明确的只是,docker是不会执行一个特定的进程的,比如systemd,这也就导致systemctl所依赖的服务不会被启动起来,从而我们也就没有办法使用systemctl。

        1. 提前启动systemd

        Linux系统的启动过程大致分为5个阶段:①内核引导;②运行init程序;③系统初始化;④建立终端;⑤用户登录操作系统。从Centos7以后,init程序就由systemd来实现,其配置文件在/usr/lib/systemd/system和/etc/systemd/system下。      学新通

         可以看到systemd包含了多个类型的服务配置,实际上systemd和之前init的区别在于init是逐个启动的,systemd支持多线程并行启动,效率上要高很多。为了提前启动systemd,可以执行/sbin/init,将其作为docker启动时的默认入口

  1.  
    C:\Users\dell>docker run -it --name pig01 --privileged centos:latest /sbin/init
  2.  
     
  3.  
    Welcome to CentOS Linux 8!
  4.  
     
  5.  
    [ OK ] Reached target Swap.
  6.  
    [ OK ] Listening on Process Core Dump Socket.
  7.  
    [ OK ] Listening on udev Control Socket.
  8.  
    [ OK ] Reached target Remote File Systems.
  9.  
    [ OK ] Listening on Journal Socket (/dev/log).
  10.  
    [ OK ] Reached target Network is Online.
  11.  
    [ OK ] Set up automount Arbitrary Executable File Formats File System Automount Point.
  12.  
    [ OK ] Started Forward Password Requests to Wall Directory Watch.
  13.  
    [ OK ] Reached target Local File Systems.
  14.  
    [ OK ] Started Dispatch Password Requests to Console Directory Watch.
  15.  
    [ OK ] Reached target Local Encrypted Volumes.
  16.  
    [ OK ] Reached target Paths.
  17.  
    [ OK ] Listening on udev Kernel Socket.
  18.  
    [ OK ] Reached target Slices.
  19.  
    [ OK ] Listening on initctl Compatibility Named Pipe.
  20.  
    [ OK ] Listening on Journal Socket.
  21.  
    Starting udev Coldplug all Devices...
  22.  
    Starting Rebuild Dynamic Linker Cache...
  23.  
    Starting Rebuild Journal Catalog...
  24.  
    Starting Restore /run/initramfs on shutdown...
  25.  
    Starting Read and set NIS domainname from /etc/sysconfig/network...
  26.  
    Starting Load/Save Random Seed...
  27.  
    Starting Journal Service...
  28.  
    Mounting Kernel Debug File System...
  29.  
    Starting Create System Users...
  30.  
    Starting Apply Kernel Variables...
  31.  
    Starting Rebuild Hardware Database...
  32.  
    [ OK ] Started Restore /run/initramfs on shutdown.
  33.  
    [ OK ] Started Read and set NIS domainname from /etc/sysconfig/network.
  34.  
    [ OK ] Mounted Kernel Debug File System.
  35.  
    [ OK ] Started Create System Users.
  36.  
    [ OK ] Started Apply Kernel Variables.
  37.  
    [ OK ] Started Rebuild Hardware Database.
  38.  
    Starting Create Static Device Nodes in /dev...
  39.  
    [ OK ] Started Rebuild Journal Catalog.
  40.  
    [ OK ] Started Load/Save Random Seed.
  41.  
    [ OK ] Started Create Static Device Nodes in /dev.
  42.  
    Starting udev Kernel Device Manager...
  43.  
    [ OK ] Started Journal Service.
  44.  
    Starting Flush Journal to Persistent Storage...
  45.  
    [ OK ] Started Flush Journal to Persistent Storage.
  46.  
    Starting Create Volatile Files and Directories...
  47.  
    [ OK ] Started Rebuild Dynamic Linker Cache.
  48.  
    Starting Update is Completed...
  49.  
    [ OK ] Started udev Coldplug all Devices.
  50.  
    [ OK ] Started udev Kernel Device Manager.
  51.  
    [ OK ] Started Create Volatile Files and Directories.
  52.  
    [ OK ] Started Update is Completed.
  53.  
    Starting Update UTMP about System Boot/Shutdown...
  54.  
    [ OK ] Started Update UTMP about System Boot/Shutdown.
  55.  
    [ OK ] Reached target System Initialization.
  56.  
    [ OK ] Started dnf makecache --timer.
  57.  
    [ OK ] Started Daily Cleanup of Temporary Directories.
  58.  
    [ OK ] Reached target Timers.
  59.  
    [ OK ] Listening on D-Bus System Message Bus Socket.
  60.  
    [ OK ] Reached target Sockets.
  61.  
    [ OK ] Reached target Basic System.
  62.  
    [ OK ] Started D-Bus System Message Bus.
  63.  
    Starting Permit User Sessions...
  64.  
    Starting dnf makecache...
  65.  
    Starting Cleanup of Temporary Directories...
  66.  
    [ OK ] Started Permit User Sessions.
  67.  
    [ OK ] Reached target Multi-User System.
  68.  
    Starting Update UTMP about System Runlevel Changes...
  69.  
    [ OK ] Started Cleanup of Temporary Directories.
  70.  
    [ OK ] Started Update UTMP about System Runlevel Changes.
  71.  
    See 'systemctl status dnf-makecache.service' for details.
学新通

        看起来是不是特别像系统启动时的样子——其实就是一摸一样的。

系统服务目录/usr/lib/systemd下边有系统(system)和用户(user),system是需要开机没有登陆情况下就能运行的程序,user是用户登录后才能运行的程序。

        然后这个程序就挂住了,需要以exec重新进入这个容器:

  1.  
    C:\Users\dell>docker exec -it pig01 bash
  2.  
    [root@6f9f323be393 /]# systemctl
  3.  
    UNIT LOAD ACTIVE SUB DESCRIPTION
  4.  
    proc-sys-fs-binfmt_misc.automount loaded active waiting Arbitrary Executable File Formats File System Automount Point
  5.  
    dev-sdc.device loaded activating tentative /dev/sdc
  6.  
    -.mount loaded active mounted Root Mount
  7.  
    dev-mqueue.mount loaded active mounted POSIX Message Queue File System
  8.  
    etc-hostname.mount loaded active mounted /etc/hostname
  9.  
    etc-hosts.mount loaded active mounted /etc/hosts
  10.  
    etc-resolv.conf.mount loaded active mounted /etc/resolv.conf
  11.  
    sys-kernel-debug.mount loaded active mounted Kernel Debug File System
  12.  
    systemd-ask-password-console.path loaded active waiting Dispatch Password Requests to Console Directory Watch
  13.  
    systemd-ask-password-wall.path loaded active waiting Forward Password Requests to Wall Directory Watch
  14.  
    init.scope loaded active running System and Service Manager
  15.  
    dbus.service loaded active running D-Bus System Message Bus
  16.  
    ldconfig.service loaded active exited Rebuild Dynamic Linker Cache
  17.  
    nis-domainname.service loaded active exited Read and set NIS domainname from /etc/sysconfig/network
  18.  
    systemd-hwdb-update.service loaded active exited Rebuild Hardware Database
  19.  
    systemd-journal-catalog-update.service loaded active exited Rebuild Journal Catalog
  20.  
    systemd-journal-flush.service loaded active exited Flush Journal to Persistent Storage
  21.  
    systemd-journald.service loaded active running Journal Service
  22.  
    systemd-random-seed.service loaded active exited Load/Save Random Seed
  23.  
    systemd-sysctl.service loaded active exited Apply Kernel Variables
  24.  
    systemd-sysusers.service loaded active exited Create System Users
  25.  
    systemd-tmpfiles-setup-dev.service loaded active exited Create Static Device Nodes in /dev
  26.  
    systemd-tmpfiles-setup.service loaded active exited Create Volatile Files and Directories
  27.  
    systemd-udev-trigger.service loaded active exited udev Coldplug all Devices
  28.  
    systemd-udevd.service loaded active running udev Kernel Device Manager
  29.  
    systemd-update-done.service loaded active exited Update is Completed
  30.  
    systemd-update-utmp.service loaded active exited Update UTMP about System Boot/Shutdown
  31.  
    systemd-user-sessions.service loaded active exited Permit User Sessions
  32.  
    -.slice loaded active active Root Slice
  33.  
    system.slice loaded active active System Slice
  34.  
    dbus.socket loaded active running D-Bus System Message Bus Socket
  35.  
    systemd-coredump.socket loaded active listening Process Core Dump Socket
  36.  
    lines 1-35
  37.  
     
  38.  
     
学新通

       systemctl也能够使用了。(使用dokken/centos-stream-8试验,如果使用官方的那个centos:latest,因为已经不更了,所以yum库会有问题,需要后面手工更改)

        为了测试一下这个ssh是否确实通了,我们另开一个容器,安装openssh-clients来测试:

  1.  
    C:\Users\dell>docker run -it --name pig02 dokken/centos-stream-8 bash
  2.  
    [root@fc88b5d2d81f /]#
  3.  
    [root@fc88b5d2d81f /]#
  4.  
    [root@fc88b5d2d81f /]#
  5.  
    [root@fc88b5d2d81f /]# yum list openssh*
  6.  
    CentOS Stream 8 - AppStream 6.7 MB/s | 26 MB 00:03
  7.  
    CentOS Stream 8 - BaseOS 2.4 MB/s | 26 MB 00:10
  8.  
    CentOS Stream 8 - Extras 30 kB/s | 18 kB 00:00
  9.  
    CentOS Stream 8 - Extras common packages 2.8 kB/s | 5.2 kB 00:01
  10.  
    Available Packages
  11.  
    openssh.x86_64 8.0p1-16.el8 baSEO((Search Engine Optimization))s
  12.  
    openssh-askpass.x86_64 8.0p1-16.el8 appstream
  13.  
    openssh-cavs.x86_64 8.0p1-16.el8 baSEO((Search Engine Optimization))s
  14.  
    openssh-clients.x86_64 8.0p1-16.el8 baSEO((Search Engine Optimization))s
  15.  
    openssh-keycat.x86_64 8.0p1-16.el8 baSEO((Search Engine Optimization))s
  16.  
    openssh-ldap.x86_64 8.0p1-16.el8 baSEO((Search Engine Optimization))s
  17.  
    openssh-server.x86_64 8.0p1-16.el8 baSEO((Search Engine Optimization))s
  18.  
    [root@fc88b5d2d81f /]# yum install -y openssh-clients
  19.  
    Last metadata expiration check: 0:00:27 ago on Fri Dec 2 04:07:55 2022.
  20.  
    Dependencies resolved.
  21.  
    ========================================================================================================================
  22.  
    Package Architecture Version Repository Size
  23.  
    ========================================================================================================================
  24.  
    Installing:
  25.  
    openssh-clients x86_64 8.0p1-16.el8 baSEO((Search Engine Optimization))s 669 k
  26.  
    Installing dependencies:
  27.  
    libedit x86_64 3.1-23.20170329cvs.el8 baSEO((Search Engine Optimization))s 102 k
  28.  
    openssh x86_64 8.0p1-16.el8 baSEO((Search Engine Optimization))s 523 k
  29.  
     
  30.  
    Transaction Summary
  31.  
    ========================================================================================================================
  32.  
    Install 3 Packages
  33.  
     
  34.  
    Total download size: 1.3 M
  35.  
    Installed size: 4.5 M
  36.  
    Downloading Packages:
  37.  
    (1/3): libedit-3.1-23.20170329cvs.el8.x86_64.rpm 1.1 MB/s | 102 kB 00:00
  38.  
    (2/3): openssh-clients-8.0p1-16.el8.x86_64.rpm 3.8 MB/s | 669 kB 00:00
  39.  
    (3/3): openssh-8.0p1-16.el8.x86_64.rpm 837 kB/s | 523 kB 00:00
  40.  
    ------------------------------------------------------------------------------------------------------------------------
  41.  
    Total 1.1 MB/s | 1.3 MB 00:01
  42.  
    Running transaction check
  43.  
    Transaction check succeeded.
  44.  
    Running transaction test
  45.  
    Transaction test succeeded.
  46.  
    Running transaction
  47.  
    Preparing : 1/1
  48.  
    Running scriptlet: openssh-8.0p1-16.el8.x86_64 1/3
  49.  
    Installing : openssh-8.0p1-16.el8.x86_64 1/3
  50.  
    Installing : libedit-3.1-23.20170329cvs.el8.x86_64 2/3
  51.  
    Installing : openssh-clients-8.0p1-16.el8.x86_64 3/3
  52.  
    Running scriptlet: openssh-clients-8.0p1-16.el8.x86_64 3/3
  53.  
    Verifying : libedit-3.1-23.20170329cvs.el8.x86_64 1/3
  54.  
    Verifying : openssh-8.0p1-16.el8.x86_64 2/3
  55.  
    Verifying : openssh-clients-8.0p1-16.el8.x86_64 3/3
  56.  
     
  57.  
    Installed:
  58.  
    libedit-3.1-23.20170329cvs.el8.x86_64 openssh-8.0p1-16.el8.x86_64 openssh-clients-8.0p1-16.el8.x86_64
  59.  
     
  60.  
    Complete!
  61.  
    [root@fc88b5d2d81f /]# ssh
  62.  
    usage: ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface]
  63.  
    [-b bind_address] [-c cipher_spec] [-D [bind_address:]port]
  64.  
    [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11]
  65.  
    [-i identity_file] [-J [user@]host[:port]] [-L address]
  66.  
    [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]
  67.  
    [-Q query_option] [-R address] [-S ctl_path] [-W host:port]
  68.  
    [-w local_tun[:remote_tun]] destination [command]
学新通

        安装openssh-server的容器,ip地址是172.17.0.2;

  1.  
    C:\Users\dell>docker run -it --name pig02 dokken/centos-stream-8 bash
  2.  
    [root@fc88b5d2d81f /]#
  3.  
    [root@fc88b5d2d81f /]#
  4.  
    [root@fc88b5d2d81f /]#
  5.  
    [root@fc88b5d2d81f /]# yum list openssh*
  6.  
    CentOS Stream 8 - AppStream 6.7 MB/s | 26 MB 00:03
  7.  
    CentOS Stream 8 - BaseOS 2.4 MB/s | 26 MB 00:10
  8.  
    CentOS Stream 8 - Extras 30 kB/s | 18 kB 00:00
  9.  
    CentOS Stream 8 - Extras common packages 2.8 kB/s | 5.2 kB 00:01
  10.  
    Available Packages
  11.  
    openssh.x86_64 8.0p1-16.el8 baSEO((Search Engine Optimization))s
  12.  
    openssh-askpass.x86_64 8.0p1-16.el8 appstream
  13.  
    openssh-cavs.x86_64 8.0p1-16.el8 baSEO((Search Engine Optimization))s
  14.  
    openssh-clients.x86_64 8.0p1-16.el8 baSEO((Search Engine Optimization))s
  15.  
    openssh-keycat.x86_64 8.0p1-16.el8 baSEO((Search Engine Optimization))s
  16.  
    openssh-ldap.x86_64 8.0p1-16.el8 baSEO((Search Engine Optimization))s
  17.  
    openssh-server.x86_64 8.0p1-16.el8 baSEO((Search Engine Optimization))s
  18.  
    [root@fc88b5d2d81f /]# yum install -y openssh-clients
  19.  
    Last metadata expiration check: 0:00:27 ago on Fri Dec 2 04:07:55 2022.
  20.  
    Dependencies resolved.
  21.  
    ========================================================================================================================
  22.  
    Package Architecture Version Repository Size
  23.  
    ========================================================================================================================
  24.  
    Installing:
  25.  
    openssh-clients x86_64 8.0p1-16.el8 baSEO((Search Engine Optimization))s 669 k
  26.  
    Installing dependencies:
  27.  
    libedit x86_64 3.1-23.20170329cvs.el8 baSEO((Search Engine Optimization))s 102 k
  28.  
    openssh x86_64 8.0p1-16.el8 baSEO((Search Engine Optimization))s 523 k
  29.  
     
  30.  
    Transaction Summary
  31.  
    ========================================================================================================================
  32.  
    Install 3 Packages
  33.  
     
  34.  
    Total download size: 1.3 M
  35.  
    Installed size: 4.5 M
  36.  
    Downloading Packages:
  37.  
    (1/3): libedit-3.1-23.20170329cvs.el8.x86_64.rpm 1.1 MB/s | 102 kB 00:00
  38.  
    (2/3): openssh-clients-8.0p1-16.el8.x86_64.rpm 3.8 MB/s | 669 kB 00:00
  39.  
    (3/3): openssh-8.0p1-16.el8.x86_64.rpm 837 kB/s | 523 kB 00:00
  40.  
    ------------------------------------------------------------------------------------------------------------------------
  41.  
    Total 1.1 MB/s | 1.3 MB 00:01
  42.  
    Running transaction check
  43.  
    Transaction check succeeded.
  44.  
    Running transaction test
  45.  
    Transaction test succeeded.
  46.  
    Running transaction
  47.  
    Preparing : 1/1
  48.  
    Running scriptlet: openssh-8.0p1-16.el8.x86_64 1/3
  49.  
    Installing : openssh-8.0p1-16.el8.x86_64 1/3
  50.  
    Installing : libedit-3.1-23.20170329cvs.el8.x86_64 2/3
  51.  
    Installing : openssh-clients-8.0p1-16.el8.x86_64 3/3
  52.  
    Running scriptlet: openssh-clients-8.0p1-16.el8.x86_64 3/3
  53.  
    Verifying : libedit-3.1-23.20170329cvs.el8.x86_64 1/3
  54.  
    Verifying : openssh-8.0p1-16.el8.x86_64 2/3
  55.  
    Verifying : openssh-clients-8.0p1-16.el8.x86_64 3/3
  56.  
     
  57.  
    Installed:
  58.  
    libedit-3.1-23.20170329cvs.el8.x86_64 openssh-8.0p1-16.el8.x86_64 openssh-clients-8.0p1-16.el8.x86_64
  59.  
     
  60.  
    Complete!
  61.  
    [root@fc88b5d2d81f /]# ssh
  62.  
    usage: ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface]
  63.  
    [-b bind_address] [-c cipher_spec] [-D [bind_address:]port]
  64.  
    [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11]
  65.  
    [-i identity_file] [-J [user@]host[:port]] [-L address]
  66.  
    [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]
  67.  
    [-Q query_option] [-R address] [-S ctl_path] [-W host:port]
  68.  
    [-w local_tun[:remote_tun]] destination [command]
学新通

        我们从client的容器登录测试一下

  1.  
    [root@fc88b5d2d81f /]# ssh root@172.17.0.2
  2.  
    The authenticity of host '172.17.0.2 (172.17.0.2)' can't be established.
  3.  
    ECDSA key fingerprint is SHA256:qIaSvGeRl5K7FEw7Es39eiUyf1tV7p0h7tPRY0YT9HA.
  4.  
    Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
  5.  
    Warning: Permanently added '172.17.0.2' (ECDSA) to the list of known hosts.
  6.  
    root@172.17.0.2's password:
  7.  
    Last failed login: Fri Dec 2 04:15:46 UTC 2022 from 172.17.0.3 on ssh:notty
  8.  
    There were 3 failed login attempts since the last successful login.
  9.  
    [root@dd1e49279724 ~]#

        从前面提示的容器号的改变可以看出,已经切换到server容器中了。

        PS1:更改密码

        dokken/centos-stream-8镜像载入容器是默认以root用户登录的,在ssh的时候需要提供密码——当然我并不知道初始密码是什么。不过解决办法也很简单,在容器内更改就是:

  1.  
    [root@dd1e49279724 system]# whoami
  2.  
    root
  3.  
    [root@dd1e49279724 system]# passwd
  4.  
    Changing password for user root.
  5.  
    New password:
  6.  
    Retype new password:
  7.  
    passwd: all authentication tokens updated successfully.
  8.  
    [root@dd1e49279724 system]#

        PS2:为什么是新开一个容器

        细心的话,可能已经看到了我们前面标红的一段字——新开一个容器?至于为什么这么麻烦,不是直接从windows的CMD直接ssh,我们后文分解。

        2.安装systemctl替代工具

        由于systemctl要以来systemd服务。那么,想在没有systemd支持的情况下使用systemctl功能的另一种方法,是使用第三方提供的systemctl替代工具gdraheim2 docker-systemctl-replacement。

        该工具基于python2脚本,所以实现需要在容器中安装python2:

  1.  
    [root@44ed0fe563f3 bin]# yum install python2 -y
  2.  
    Last metadata expiration check: 0:00:12 ago on Fri Dec 2 04:55:56 2022.
  3.  
    Dependencies resolved.
  4.  
    ======================================================================================================================================================================
  5.  
    Package Architecture Version Repository Size
  6.  
    ======================================================================================================================================================================
  7.  
    Installing:
  8.  
    python2 x86_64 2.7.18-11.module_el8.7.0 1179 42dadd5f appstream 110 k
  9.  
    Installing dependencies:
  10.  
    python2-libs x86_64 2.7.18-11.module_el8.7.0 1179 42dadd5f appstream 6.0 M
  11.  
    python2-pip-wheel noarch 9.0.3-19.module_el8.6.0 987 71f62bb6 appstream 892 k
  12.  
    python2-setuptools-wheel noarch 39.0.1-13.module_el8.5.0 743 cd2f5d28 appstream 287 k
  13.  
    Installing weak dependencies:
  14.  
    python2-pip noarch 9.0.3-19.module_el8.6.0 987 71f62bb6 appstream 1.6 M
  15.  
    python2-setuptools noarch 39.0.1-13.module_el8.5.0 743 cd2f5d28 appstream 642 k
  16.  
    Enabling module streams:
  17.  
    python27 2.7
  18.  
     
  19.  
    Transaction Summary
  20.  
    ======================================================================================================================================================================
  21.  
    Install 6 Packages
  22.  
     
  23.  
    Total download size: 9.5 M
  24.  
    Installed size: 37 M
  25.  
    Downloading Packages:
  26.  
    (1/6): python2-2.7.18-11.module_el8.7.0 1179 42dadd5f.x86_64.rpm 1.0 MB/s | 110 kB 00:00
  27.  
    (2/6): python2-pip-wheel-9.0.3-19.module_el8.6.0 987 71f62bb6.noarch.rpm 2.3 MB/s | 892 kB 00:00
  28.  
    (3/6): python2-pip-9.0.3-19.module_el8.6.0 987 71f62bb6.noarch.rpm 2.4 MB/s | 1.6 MB 00:00
  29.  
    (4/6): python2-setuptools-39.0.1-13.module_el8.5.0 743 cd2f5d28.noarch.rpm 2.5 MB/s | 642 kB 00:00
  30.  
    (5/6): python2-setuptools-wheel-39.0.1-13.module_el8.5.0 743 cd2f5d28.noarch.rpm 2.4 MB/s | 287 kB 00:00
  31.  
    (6/6): python2-libs-2.7.18-11.module_el8.7.0 1179 42dadd5f.x86_64.rpm 4.4 MB/s | 6.0 MB 00:01
  32.  
    ----------------------------------------------------------------------------------------------------------------------------------------------------------------------
  33.  
    Total 5.2 MB/s | 9.5 MB 00:01
  34.  
    Running transaction check
  35.  
    Transaction check succeeded.
  36.  
    Running transaction test
  37.  
    Transaction test succeeded.
  38.  
    Running transaction
  39.  
    Preparing : 1/1
  40.  
    Installing : python2-setuptools-wheel-39.0.1-13.module_el8.5.0 743 cd2f5d28.noarch 1/6
  41.  
    Installing : python2-pip-wheel-9.0.3-19.module_el8.6.0 987 71f62bb6.noarch 2/6
  42.  
    Installing : python2-libs-2.7.18-11.module_el8.7.0 1179 42dadd5f.x86_64 3/6
  43.  
    Installing : python2-pip-9.0.3-19.module_el8.6.0 987 71f62bb6.noarch 4/6
  44.  
    Installing : python2-setuptools-39.0.1-13.module_el8.5.0 743 cd2f5d28.noarch 5/6
  45.  
    Installing : python2-2.7.18-11.module_el8.7.0 1179 42dadd5f.x86_64 6/6
  46.  
    Running scriptlet: python2-2.7.18-11.module_el8.7.0 1179 42dadd5f.x86_64 6/6
  47.  
    Verifying : python2-2.7.18-11.module_el8.7.0 1179 42dadd5f.x86_64 1/6
  48.  
    Verifying : python2-libs-2.7.18-11.module_el8.7.0 1179 42dadd5f.x86_64 2/6
  49.  
    Verifying : python2-pip-9.0.3-19.module_el8.6.0 987 71f62bb6.noarch 3/6
  50.  
    Verifying : python2-pip-wheel-9.0.3-19.module_el8.6.0 987 71f62bb6.noarch 4/6
  51.  
    Verifying : python2-setuptools-39.0.1-13.module_el8.5.0 743 cd2f5d28.noarch 5/6
  52.  
    Verifying : python2-setuptools-wheel-39.0.1-13.module_el8.5.0 743 cd2f5d28.noarch 6/6
  53.  
     
  54.  
    Installed:
  55.  
    python2-2.7.18-11.module_el8.7.0 1179 42dadd5f.x86_64 python2-libs-2.7.18-11.module_el8.7.0 1179 42dadd5f.x86_64
  56.  
    python2-pip-9.0.3-19.module_el8.6.0 987 71f62bb6.noarch python2-pip-wheel-9.0.3-19.module_el8.6.0 987 71f62bb6.noarch
  57.  
    python2-setuptools-39.0.1-13.module_el8.5.0 743 cd2f5d28.noarch python2-setuptools-wheel-39.0.1-13.module_el8.5.0 743 cd2f5d28.noarch
  58.  
     
  59.  
    Complete!
  60.  
    [root@44ed0fe563f3 bin]#
学新通

         从github上将替代脚本拷贝到/usr/bin/下,替换systemctl,并赋予执行权限:

  1.  
    [root@44ed0fe563f3 bin]# wget https://raw.githubusercontent.com/gdraheim/docker-systemctl-replacement/master/files/docker/systemctl.py -O /usr/bin/systemctl
  2.  
    --2022-12-02 05:01:51-- https://raw.githubusercontent.com/gdraheim/docker-systemctl-replacement/master/files/docker/systemctl.py
  3.  
    Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.110.133, 185.199.109.133, 185.199.111.133, ...
  4.  
    Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.110.133|:443... connected.
  5.  
    HTTP request sent, awaiting response... 200 OK
  6.  
    Length: 291424 (285K) [text/plain]
  7.  
    Saving to: ‘/usr/bin/systemctl’
  8.  
     
  9.  
    /usr/bin/systemctl 100%[===================================================================================>] 284.59K 1.65MB/s in 0.2s
  10.  
     
  11.  
    2022-12-02 05:01:51 (1.65 MB/s) - ‘/usr/bin/systemctl’ saved [291424/291424]
  12.  
     
  13.  
    [root@44ed0fe563f3 bin]# chmod a x /usr/bin/systemctl

         执行,虽然格式上没有官方的好看,但总是能用了嘛:

  1.  
    [root@44ed0fe563f3 /]# systemctl
  2.  
    README.service loaded inactive dead
  3.  
    arp-ethers.service loaded inactive dead Load static arp entries
  4.  
    atd.service loaded inactive dead Job spooling tools
  5.  
    autovt@.service loaded inactive dead Getty on
  6.  
    basic.target loaded inactive dead Basic System
  7.  
    bluetooth.target loaded active dead Bluetooth
  8.  
    boot-complete.target loaded active dead Boot Completion Check
  9.  
    console-getty.service loaded inactive dead
  10.  
    …………
  11.  
    …………
  12.  
    time-sync.target loaded active dead System Time Synchronized
  13.  
    timers.target loaded active dead Timers
  14.  
    tmp.mount loaded unknown dead Temporary Directory (/tmp)
  15.  
    umount.target loaded active dead Unmount All Filesystems
  16.  
    unbound-anchor.service loaded inactive dead update of the root trust anchor for DNSSEC validation in unbound
  17.  
    unbound-anchor.timer loaded unknown dead daily update of the root trust anchor for DNSSEC
  18.  
    user-runtime-dir@.service loaded inactive dead User runtime directory /run/user/
  19.  
    user.slice loaded unknown dead User and Session Slice
  20.  
    user@.service loaded inactive dead User Manager for UID
  21.  
     
  22.  
    185 loaded units listed.
  23.  
    To show all installed unit files use 'systemctl list-unit-files'.
  24.  
    [root@44ed0fe563f3 /]#
学新通

        回头再来看一看作者提供的dockerfile:

  1.  
    FROM centos:7.7.1908
  2.  
     
  3.  
    LABEL __copyright__="(C) Guido U. Draheim, licensed under the EUPL" \
  4.  
    __version__="1.4.4147"
  5.  
    ARG PASSWORD=Test.P@ssw0rd
  6.  
    EXPOSE 22
  7.  
     
  8.  
    # RUN yum install -y epel-release
  9.  
    RUN yum search sshd
  10.  
    RUN yum install -y openssh-server
  11.  
    RUN rpm -q --list openssh-server
  12.  
    COPY files/docker/systemctl.py /usr/bin/systemctl
  13.  
    RUN : \
  14.  
    ; mkdir /etc/systemd/system/sshd-keygen.service.d \
  15.  
    ; { echo "[Install]"; echo "WantedBy=multi-user.target"; } \
  16.  
    > /etc/systemd/system/sshd-keygen.service.d/enabled.conf
  17.  
    RUN systemctl enable sshd-keygen
  18.  
    RUN systemctl enable sshd
  19.  
    #
  20.  
    RUN yum install -y openssh-clients
  21.  
    RUN rpm -q --list openssh-clients
  22.  
    RUN useradd -g nobody testuser
  23.  
    RUN echo $PASSWORD | passwd --stdin testuser
  24.  
    RUN date -I > /home/testuser/date.txt
  25.  
    CMD /usr/bin/systemctl
学新通

        作者给出了很多版本和服务的dockerfile,可以用来编译对应的images。以上面ssh的为例,实际就是在基础映像上安装了openssl,替换systemctl,然后启动ssh服务。这里一个需要注意的问题是,默认的程序入口设置在了/user/bin/systemctl。这个应该跟docker的管理机制有关。据该工具作者的说法,docker将CMD/ENTRYPOINT启动的程序的PID置为1,而docker向容器发送的stop命令,只有PID为1的程序能收到。这个白话一点,就是容器的生命周期管理等同于对容器中PID=1的进程的管理,不能随心所欲——比如不是我们正经用来干活的app,而是某个服务进程等等。所以,这里作者以这个替换的systemctl作为默认程序启动,在其内部还处理了一部分docker进程管理的内容;感兴趣的话可以cat一下systemctl.py的代码,搜索一下'pid'关键字。

        二、Service那些事

        不管是直接/sbin/init的方法,还是第三方工具替代的方法,总是给人一种不太稳妥的感觉。一个是一次启动一大堆,也不知道哪个有用哪个没用,环境对或不对——实际总能不经意看到各种报错信息;另一种是把生杀大权完全交给第三方,不知道它在那倒腾啥。相比之下,我们还是比较喜欢纯手撸的感觉,比如是否可以以非systemctl的方式将服务启动起来?

        答案当然是完全可以,服务也是一个程序而已。

        前面说到,与服务相关的配置文件,在系统中有2个地方,一个是/usr/lib/systemd/system,一个是etc/system/systemd。根据菜鸟教程上的解释:

        etc  是etcetera(等等)的简写,该目录用来存放所有的系统管理所需要的配置文件,有那么一点类似于windows下的注册表。

        usr  是unix share resource的简写,该目录用来存放用户应用程序,类似于windows下的program files目录。

        据说,系统的服务存放在/usr/lib/systemd/system/下,用户的存放在/etc/systemd/user/下,虽然两边的systemd下其实都有system和user子目录。

        手工启动服务,实际上只不过是根据服务配置文件描述,准备好服务的启动环境,然后以daemon方式启动服务的程序而已。

        1.  .service文件格式

        继续以ssh为例。载入dokken/centos-stream-8镜像,yum安装openssl-server后,在/usr/lib/systemd/system下,可以找到sshd.service文件,它指出了ssh服务启动的条件,及其与其他服务的关系:

  1.  
    [root@6f8f39825b78 /]# cd /usr/lib/systemd
  2.  
    [root@6f8f39825b78 systemd]# cd system
  3.  
    [root@6f8f39825b78 system]# ls
  4.  
    arp-ethers.service network.target systemd-backlight@.service
  5.  
    …… ……
  6.  
    initrd-cleanup.service sshd-keygen.target systemd-udev-trigger.service
  7.  
    initrd-fs.target sshd-keygen@.service systemd-udev-trigger.service.d
  8.  
    initrd-parse-etc.service sshd.service systemd-udevd-control.socket
  9.  
    initrd-root-device.target sshd.socket systemd-udevd-kernel.socket
  10.  
    initrd-root-fs.target sshd@.service systemd-udevd.service
  11.  
    …… ……
  12.  
    network-pre.target systemd-ask-password-wall.service
  13.  
    [root@6f8f39825b78 system]# cat sshd.service
  14.  
    [Unit]
  15.  
    Description=OpenSSH server daemon
  16.  
    Documentation=man:sshd(8) man:sshd_config(5)
  17.  
    After=network.target sshd-keygen.target
  18.  
    Wants=sshd-keygen.target
  19.  
     
  20.  
    [Service]
  21.  
    Type=notify
  22.  
    EnvironmentFile=-/etc/crypto-policies/back-ends/opensshserver.config
  23.  
    EnvironmentFile=-/etc/sysconfig/sshd
  24.  
    ExecStart=/usr/sbin/sshd -D $OPTIONS $CRYPTO_POLICY
  25.  
    ExecReload=/bin/kill -HUP $MAINPID
  26.  
    KillMode=process
  27.  
    Restart=on-failure
  28.  
    RestartSec=42s
  29.  
     
  30.  
    [Install]
  31.  
    WantedBy=multi-user.target
  32.  
    [root@6f8f39825b78 system]#
学新通

        (1)unit字段:描述依赖关系与启动顺序

        Description:服务的描述

        Documention:服务的文档

        After:表示不涉及依赖关系的启动顺序,本服务在该服务之后启动。不涉及依赖关系的含义指即使前序服务未启动,也不至于影响本服务的正常启动,但可能造成功能性问题。

        Before:不涉及依赖关系的启动顺序,本服务在该服务之前启动。

        Wants:表示本服务和某服务存在弱依赖关系,该服务停止运行或退出不影响本服务继续运行。

        Requires:表示强依赖关系,即该服务停止运行或退出,则本服务也必须停止运行

        (2)service字段:描述环境变量,启动、重启与停止方式

        Type:服务启动类型。simple为立即启动,并不会启动其它服务(子进程方式);notify,与simple一样,不同在于其会向systemd回发一个通知信号;forking,该服务fork,且父进程退出后服务启动成功,使用该类型需要指定PIDFile,以便systemd管理;oneshot,适用于启动后完成一项操作立即退出的服务;dbus,当指定的busname出现在Dbus总线上时,服务启动成功。

        EnvironmentFile:环境配置文件,用于配置服务程序运行时需要的环境变量

        ExecStart:指定启动服务的命令(程序)及启动的命令行方式

        ExeStartPre/ExeStartPost:指定在服务启动前后需要执行的用户自定义脚本

        ExecStop:指定停止服务的命令及命令行方式

        (3)install字段:描述开机自启动方式

        RequiredBy:强依赖关系。

        Also:指出需要被一起安装的协同服务。

        DefaultInstance:允许运行的实例个数。

        WantedBy字段:表示该服务所在的Target组。Target表示一组服务,WantedBy=multi-user.target指的是服务所在的Target组是multi-user.target。multi-user.target时systemd的默认启动组,在该组内的服务都会开机启动。

        2.ssh服务配置

        根据上面介绍的的服务配置字段,剥一下sshd.service的洋葱:        

        (1)启动顺序

        After=network.target sshd-keygen.target。这个必须的,如果网络都不同这事就不用搞了

        (2)依赖关系

        Wants=sshd-keygen.target。指sshd服务对于sshd-keygen这个服务组是弱依赖关系

        我们知道sshd-keygen是ssh的密钥生成与管理程序。那么sshd-keygen这个服务组里有什么呢?:

  1.  
    [root@6f8f39825b78 system]# cat sshd-keygen.target
  2.  
    [Unit]
  3.  
    Wants=sshd-keygen@rsa.service
  4.  
    Wants=sshd-keygen@ecdsa.service
  5.  
    Wants=sshd-keygen@ed25519.service
  6.  
    PartOf=sshd.service

       从配置文件可以看出,这个服务组里包括一系列密码算法服务。 注意到服务名称里面的@,@符号前是基础的服务名,@符号后面是服务的参数。所以这3个服务的配置方式,其实都在sshd-kegen@.service里面:

  1.  
    [root@6f8f39825b78 system]# cat sshd-keygen@.service
  2.  
    [Unit]
  3.  
    Description=OpenSSH %i Server Key Generation
  4.  
    ConditionFileNotEmpty=|!/etc/ssh/ssh_host_%i_key
  5.  
     
  6.  
    [Service]
  7.  
    Type=oneshot
  8.  
    EnvironmentFile=-/etc/sysconfig/sshd
  9.  
    ExecStart=/usr/libexec/openssh/sshd-keygen %i
  10.  
     
  11.  
    [Install]
  12.  
    WantedBy=sshd-keygen.target

       这里提一句这个ConditionFileNotEmpty,应该是存在这个文件的意思,但是值里面多了一个逻辑反的符号,应该是说,前提条件是这几个文件必须不存在。事实上,在启动服务前,这几个文件确实不存在。

        首先是需要设置环境etc/sysconfig/sshd,这个文件里面实际就是环境变量:

  1.  
    [root@6f8f39825b78 sysconfig]# cat sshd
  2.  
    # Configuration file for the sshd service.
  3.  
     
  4.  
    # The server keys are automatically generated if they are missing.
  5.  
    # To change the automatic creation, adjust sshd.service options for
  6.  
    # example using systemctl enable sshd-keygen@dsa.service to allow creation
  7.  
    # of DSA key or systemctl mask sshd-keygen@rsa.service to disable RSA key
  8.  
    # creation.
  9.  
     
  10.  
    # Do not change this option unless you have hardware random
  11.  
    # generator and you REALLY know what you are doing
  12.  
     
  13.  
    SSH_USE_STRONG_RNG=0
  14.  
    # SSH_USE_STRONG_RNG=1
  15.  
     
  16.  
    # System-wide crypto policy:
  17.  
    # To opt-out, uncomment the following line
  18.  
    # CRYPTO_POLICY=
  19.  
    [root@6f8f39825b78 sysconfig]#
学新通

        然后执行/usr/libexec/openssh/sshd-keygen命令,以上述那些算法名称为参数。

        (3)环境变量

        EnvironmentFile=-/etc/crypto-policies/back-ends/opensshserver.config
        EnvironmentFile=-/etc/sysconfig/sshd

        其中一个和sshd-keygen相同,另一个如下:        

  1.  
    [root@6f8f39825b78 sysconfig]# cat /etc/crypto-policies/back-ends/opensshserver.config
  2.  
    CRYPTO_POLICY='-oCiphers=aes256-gcm@openssh.com,chacha20-poly1305@openssh.com,aes256-ctr,aes256-cbc,aes128-gcm@openssh.com,aes128-ctr,aes128-cbc -oMACs=hmac-sha2-256-etm@openssh.com,hmac-sha1-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha1,umac-128@openssh.com,hmac-sha2-512 -oGSSAPIKexAlgorithms=gss-curve25519-sha256-,gss-nistp256-sha256-,gss-group14-sha256-,gss-group16-sha512-,gss-gex-sha1-,gss-group14-sha1- -oKexAlgorithms=curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha256,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1 -oHostKeyAlgorithms=ecdsa-sha2-nistp256,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com,ssh-rsa,ssh-rsa-cert-v01@openssh.com -oPubkeyAcceptedKeyTypes=ecdsa-sha2-nistp256,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521,ecdsa-sha2-nistp521-cert-v01@openssh.com,ssh-ed25519,ssh-ed25519-cert-v01@openssh.com,rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com,rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com,ssh-rsa,ssh-rsa-cert-v01@openssh.com -oCASignatureAlgorithms=ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,ssh-ed25519,rsa-sha2-256,rsa-sha2-512,ssh-rsa'[root@6f8f39825b78 sysconfig]#

         就是对加密算法策略的设置

        (4)启动方式

        ExecStart=/usr/sbin/sshd -D $OPTIONS $CRYPTO_POLICY

        可以看到,其实就是以daemon方式启动sshd,参数是已经在配置文件中明确的环境变量。

        2. 启动sshd服务

        所以,根据配置文件翻译成shell脚本,我们就可以一步一步启动sshd了。比如我们在/下创建了一个test.sh文件,编辑如下:        

  1.  
    [root@6f8f39825b78 /]# cat test.sh
  2.  
    source /etc/sysconfig/sshd
  3.  
    source /etc/crypto-policies/back-ends/opensshserver.config
  4.  
    /usr/libexec/openssh/sshd-keygen rsa
  5.  
    /usr/libexec/openssh/sshd-keygen ecdsa
  6.  
    /usr/libexec/openssh/sshd-keygen ed25519
  7.  
    echo OPTIONS=$OPTIONS
  8.  
    echo CRYPTO-POLICY=$CRYPTO_POLICY
  9.  
    /usr/sbin/sshd -D $OPTIONS $CRYPTO_POLICY

        执行

  1.  
    [root@6f8f39825b78 /]# chmod a x ./test.sh
  2.  
    [root@6f8f39825b78 /]# ./test.sh

        完毕以后,到sshd-keygen@.service里面ConditionFileNotEmpty=|!/etc/ssh/ssh_host_%i_key所指示的路径,发现这些文件已经成功生成了:

  1.  
    [root@6f8f39825b78 ssh]# pwd
  2.  
    /etc/ssh
  3.  
    [root@6f8f39825b78 ssh]# ls
  4.  
    moduli ssh_host_ecdsa_key.pub ssh_host_ed25519_key.pub ssh_host_rsa_key.pub
  5.  
    ssh_host_ecdsa_key ssh_host_ed25519_key ssh_host_rsa_key sshd_config
  6.  
    [root@6f8f39825b78 ssh]#

          从另一个容器中访问:

  1.  
    [root@723680cac971 /]# ssh root@172.17.0.2
  2.  
    The authenticity of host '172.17.0.2 (172.17.0.2)' can't be established.
  3.  
    ECDSA key fingerprint is SHA256:KL2b74VslHW8Lgs8z/2EYBONdt0YhFl21L1HaqkD3/s.
  4.  
    Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
  5.  
    Warning: Permanently added '172.17.0.2' (ECDSA) to the list of known hosts.
  6.  
    root@172.17.0.2's password:
  7.  
    [root@6f8f39825b78 ~]#

        成功。

        3. 配置开机启动

        所谓配置开机启动,实际是需要利用dockerfile文件的RUN命令,RUN可以作为构建docker image时运行的命令,将之前我们手撸的sh COPY到image中,然后在RUN中执行。基于这一点生成新的镜像来使用。这个和我们之前提到的gdraheim2 docker-systemctl-replacement的dockerfile的做法是一样的。因为要抢饭去,所以就不测试了哈。

        三、容器的网络问题

        然而,解决服务问题并不是docker最大的坑——网络才是。

        鉴于关于docker的组网有大量的文章介绍,这里不赘述了,之说结果——结果就是,docker desktop无法解决从宿主机向容器的网络路由,从而除非使用docker的网络映射机制(就是-p -P 等等将端口映射到主机的端口,然后使用localhost加端口来访问),从宿主机机器外部是无法访问docker的。从这个角度看,更应该在docker视作进程隔离的工具,而不应该将其作为虚拟机。

        下面通过几个实验来说明这个问题。

        1.在Linux上的Docker网络

        第一个实验,是在我的windows主机上安装vmware,vmware上安装centos作为docker的宿主机,并在这个centos中启动一个centos的docker:

        (1)centos宿主机上的网络配置

学新通

                 宿主机上,Vmware安装Centos时使用NAT配置方式,使用的Vmnet8.

        (2)Linux宿主机的网络配置        

  1.  
    [root@pig ~]# ifconfig
  2.  
    docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
  3.  
    inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
  4.  
    ether …… txqueuelen 0 (Ethernet)
  5.  
    RX packets 114 bytes 3192 (3.1 KiB)
  6.  
    RX errors 0 dropped 0 overruns 0 frame 0
  7.  
    TX packets 19 bytes 2141 (2.0 KiB)
  8.  
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
  9.  
     
  10.  
    ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
  11.  
    inet 192.168.21.11 netmask 255.255.255.0 broadcast 192.168.21.255
  12.  
    inet6 fe80::20c:29ff:fec0:ce6f prefixlen 64 scopeid 0x20<link>
  13.  
    ether …… txqueuelen 1000 (Ethernet)
  14.  
    RX packets 102612 bytes 149526664 (142.5 MiB)
  15.  
    RX errors 0 dropped 0 overruns 0 frame 0
  16.  
    TX packets 23494 bytes 1351782 (1.2 MiB)
  17.  
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
  18.  
    …………………………
  19.  
    …………………………
  20.  
    [root@pig ~]# ip route show
  21.  
    default via 192.168.21.2 dev ens160 proto static metric 100
  22.  
    192.168.21.0/24 dev ens160 proto kernel scope link src 192.168.21.11 metric 100
学新通

        Linux下的docker宿主机,除了本机网卡(192.168.21.11)以外,还能看到传说中的docker0网卡。 注意这里网关,时192.168.21.2。

        (3)容器中的网络配置        

  1.  
    [root@8a32b6f65a57 /]# ip address
  2.  
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  3.  
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  4.  
    inet 127.0.0.1/8 scope host lo
  5.  
    valid_lft forever preferred_lft forever
  6.  
    17: eth0@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  7.  
    link/ether …… brd ff:ff:ff:ff:ff:ff link-netnsid 0
  8.  
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
  9.  
    valid_lft forever preferred_lft forever
  10.  
    [root@8a32b6f65a57 /]# ip route show
  11.  
    default via 172.17.0.1 dev eth0
  12.  
    172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2
  13.  
     

        容器中,网络地址为172.17.0.2 

        (4)Ping 测试

        Ping测试之前,要把防火墙关闭,以免半天测了个寂寞。

        windows 到 docker宿主机

  1.  
    C:\Users\lhyzw>ping 192.168.21.11
  2.  
     
  3.  
    正在 Ping 192.168.21.11 具有 32 字节的数据:
  4.  
    来自 192.168.21.11 的回复: 字节=32 时间<1ms TTL=64
  5.  
    来自 192.168.21.11 的回复: 字节=32 时间<1ms TTL=64
  6.  
    来自 192.168.21.11 的回复: 字节=32 时间<1ms TTL=64

        docker宿主机到windows主机

  1.  
    [root@pig ~]# ping 192.168.21.1
  2.  
    PING 192.168.21.1 (192.168.21.1) 56(84) bytes of data.
  3.  
    64 bytes from 192.168.21.1: icmp_seq=1 ttl=64 time=0.829 ms
  4.  
    64 bytes from 192.168.21.1: icmp_seq=2 ttl=64 time=0.508 ms
  5.  
    64 bytes from 192.168.21.1: icmp_seq=3 ttl=64 time=0.616 ms

       docker宿主机到容器

  1.  
    [root@pig ~]# ping 172.17.0.2
  2.  
    PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
  3.  
    64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.164 ms
  4.  
    64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.109 ms
  5.  
    64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.069 ms

        容器到docker宿主机

  1.  
    [root@d8436f439c04 /]# ping 192.168.21.11
  2.  
    PING 192.168.21.11 (192.168.21.11) 56(84) bytes of data.
  3.  
    64 bytes from 192.168.21.11: icmp_seq=1 ttl=64 time=0.227 ms
  4.  
    64 bytes from 192.168.21.11: icmp_seq=2 ttl=64 time=0.074 ms
  5.  
    64 bytes from 192.168.21.11: icmp_seq=3 ttl=64 time=0.082 ms

        容器到windows

  1.  
    [root@d8436f439c04 /]# ping 192.168.21.1
  2.  
    PING 192.168.21.1 (192.168.21.1) 56(84) bytes of data.
  3.  
    64 bytes from 192.168.21.1: icmp_seq=1 ttl=63 time=1.70 ms
  4.  
    64 bytes from 192.168.21.1: icmp_seq=2 ttl=63 time=0.684 ms
  5.  
    64 bytes from 192.168.21.1: icmp_seq=3 ttl=63 time=0.493 ms

        windows到容器

  1.  
    C:\Users\lhyzw>ping 172.17.0.2
  2.  
    正在 Ping 172.17.0.2 具有 32 字节的数据:
  3.  
    请求超时。
  4.  
    请求超时。

        (5)连接windows到容器

        从Windows连接到容器不通,是因为windows并不知道Vmware中的docker0下有个172.17.0.0/16的网段。这个没关系,在windows下使用超级管理员打开CMD,执行route add加一条路由,将172.17.0.0/16网段的报文流转到Vmware中的docker宿主机就行了。

  1.  
    PS C:\Users\lhyzw> route add 172.17.0.0 mask 255.255.0.0 192.168.21.11
  2.  
    操作完成!
  3.  
    PS C:\Users\lhyzw> ping 172.17.0.2
  4.  
     
  5.  
    正在 Ping 172.17.0.2 具有 32 字节的数据:
  6.  
    来自 172.17.0.2 的回复: 字节=32 时间<1ms TTL=63
  7.  
    来自 172.17.0.2 的回复: 字节=32 时间<1ms TTL=63
  8.  
     
  9.  
    172.17.0.2 的 Ping 统计信息:
  10.  
    数据包: 已发送 = 2,已接收 = 2,丢失 = 0 (0% 丢失),
  11.  
    往返行程的估计时间(以毫秒为单位):
  12.  
    最短 = 0ms,最长 = 0ms,平均 = 0ms
  13.  
    Control-C
  14.  
    PS C:\Users\lhyzw> ping 172.17.0.1
  15.  
     
  16.  
    正在 Ping 172.17.0.1 具有 32 字节的数据:
  17.  
    来自 172.17.0.1 的回复: 字节=32 时间<1ms TTL=64
  18.  
    来自 172.17.0.1 的回复: 字节=32 时间=1ms TTL=64
  19.  
    来自 172.17.0.1 的回复: 字节=32 时间<1ms TTL=64
  20.  
     
  21.  
    172.17.0.1 的 Ping 统计信息:
  22.  
    数据包: 已发送 = 3,已接收 = 3,丢失 = 0 (0% 丢失),
  23.  
    往返行程的估计时间(以毫秒为单位):
  24.  
    最短 = 0ms,最长 = 1ms,平均 = 0ms
学新通

        2.在windows docker desktop上的网络

        实际上,基于windows docker desktop来使用容器,本质上和安装Vmware,使用Vmware上的centos作为docker宿主机是一样的。只不过此时替换Vmware的,是wsl中的Ubuntu而已。

  1.  
    PS C:\Users\lhyzw> wsl -l
  2.  
    适用于 Linux 的 Windows 子系统分发:
  3.  
    Ubuntu (默认)
  4.  
    docker-desktop
  5.  
    docker-desktop-data
  6.  
    PS C:\Users\lhyzw>

        (1)Windows网络设置

        Windows的网络设置与前面并无两样。但是需要提一下的是,在Win10下,观察网络适配器,会发现一个名为wsl的虚拟适配器,但是在win11下没有。不过使用ipconfig命令,还是能够看到的,不知缘故,也许是因为该适配器默认隐藏的原因。

        win10

学新通

         win11

学新通

         win11下的命令行方式查看适配器结果:

  1.  
    PS C:\Users\lhyzw> ipconfig
  2.  
    Windows IP 配置
  3.  
    以太网适配器 VMware Network Adapter VMnet1:
  4.  
    连接特定的 DNS 后缀 . . . . . . . :
  5.  
    本地链接 IPv6 地址. . . . . . . . : fe80::dd77:d5f2:85e8:29e4%7
  6.  
    IPv4 地址 . . . . . . . . . . . . : 192.168.70.1
  7.  
    子网掩码 . . . . . . . . . . . . : 255.255.255.0
  8.  
    默认网关. . . . . . . . . . . . . :
  9.  
    以太网适配器 VMware Network Adapter VMnet8:
  10.  
    连接特定的 DNS 后缀 . . . . . . . :
  11.  
    本地链接 IPv6 地址. . . . . . . . : fe80::97ff:5834:a003:eabe%4
  12.  
    IPv4 地址 . . . . . . . . . . . . : 192.168.21.1
  13.  
    子网掩码 . . . . . . . . . . . . : 255.255.255.0
  14.  
    默认网关. . . . . . . . . . . . . :
  15.  
    无线局域网适配器 WLAN:
  16.  
    连接特定的 DNS 后缀 . . . . . . . :
  17.  
    IPv6 地址 . . . . . . . . . . . . :
  18.  
    临时 IPv6 地址. . . . . . . . . . :
  19.  
    本地链接 IPv6 地址. . . . . . . . :
  20.  
    IPv4 地址 . . . . . . . . . . . . : 192.168.1.26
  21.  
    子网掩码 . . . . . . . . . . . . : 255.255.255.0
  22.  
    默认网关. . . . . . . . . . . . . :
  23.  
    192.168.1.1
  24.  
    以太网适配器 vEthernet (WSL):
  25.  
    连接特定的 DNS 后缀 . . . . . . . :
  26.  
    本地链接 IPv6 地址. . . . . . . . : fe80::696d:4cf5:ade2:eee2`
  27.  
    IPv4 地址 . . . . . . . . . . . . : 172.23.160.1
  28.  
    子网掩码 . . . . . . . . . . . . : 255.255.240.0
  29.  
    默认网关. . . . . . . . . . . . . :
学新通

        或者直接找它的名字:

  1.  
    PS C:\Users\lhyzw>  Get-NetAdapter -IncludeHidden 'vEthernet (WSL)' | Get-NetIPAddress
  2.  
     
  3.  
     
  4.  
    IPAddress : fe80::696d:4cf5:ade2:eee2`
  5.  
    InterfaceIndex : 60
  6.  
    InterfaceAlias : vEthernet (WSL)
  7.  
    AddressFamily : IPv6
  8.  
    Type : Unicast
  9.  
    PrefixLength : 64
  10.  
    PrefixOrigin : WellKnown
  11.  
    SuffixOrigin : Link
  12.  
    AddressState : Preferred
  13.  
    ValidLifetime :
  14.  
    PreferredLifetime :
  15.  
    SkipAsSource : False
  16.  
    PolicyStore : ActiveStore
  17.  
     
  18.  
    IPAddress : 172.23.160.1
  19.  
    InterfaceIndex : 60
  20.  
    InterfaceAlias : vEthernet (WSL)
  21.  
    AddressFamily : IPv4
  22.  
    Type : Unicast
  23.  
    PrefixLength : 20
  24.  
    PrefixOrigin : Manual
  25.  
    SuffixOrigin : Manual
  26.  
    AddressState : Preferred
  27.  
    ValidLifetime :
  28.  
    PreferredLifetime :
  29.  
    SkipAsSource : False
  30.  
    PolicyStore : ActiveStore
学新通

         (2)宿主机WSL网络设置

        确认Ubuntu是默认的子系统,否则下面的操作可能会报错。如果不是,可以使用--setdefault参数指定默认子系统,或者在使用wsl启动子系统的时候使用-d参数明确要启动的子系统。

  1.  
    PS C:\Users\lhyzw> wsl
  2.  
    To run a command as administrator (user "root"), use "sudo <command>".
  3.  
    See "man sudo_root" for details.
  4.  
    pig@LAPTOP-SA9UAFHF:/mnt/c/Users/lhyzw$ ip address
  5.  
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  6.  
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  7.  
    inet 127.0.0.1/8 scope host lo
  8.  
    valid_lft forever preferred_lft forever
  9.  
    inet6 ::1/128 scope host
  10.  
    valid_lft forever preferred_lft forever
  11.  
    2: bond0: <BROADCAST,MULTICAST,MASTER> mtu 1500 qdisc noop state DOWN group default qlen 1000
  12.  
    link/ether …… brd ff:ff:ff:ff:ff:ff
  13.  
    3: dummy0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
  14.  
    link/ether …… brd ff:ff:ff:ff:ff:ff
  15.  
    4: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
  16.  
    link/ipip 0.0.0.0 brd 0.0.0.0
  17.  
    5: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
  18.  
    link/sit 0.0.0.0 brd 0.0.0.0
  19.  
    6: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
  20.  
    link/ether …… brd ff:ff:ff:ff:ff:ff
  21.  
    inet 172.23.162.71/20 brd 172.23.175.255 scope global eth0
  22.  
    valid_lft forever preferred_lft forever
  23.  
    inet6 fe80::215:5dff:fe0a:6609/64 scope link
  24.  
    valid_lft forever preferred_lft forever
  25.  
    pig@LAPTOP-SA9UAFHF:/mnt/c/Users/lhyzw$ ip route show
  26.  
    default via 172.23.160.1 dev eth0 proto kernel
  27.  
    172.23.160.0/20 dev eth0 proto kernel scope link src 172.23.162.71
学新通

        可以看到,宿主机WSL上的ubuntu,网络设置为172.23.162.71 ,网关是172.23.160.1。但是改宿主机上不存在传说中的docker0虚拟适配器。

        (3)容器上的网络配置

        在WSL中启动容器,进入容器中查看可以发现,其网络配置和前面基本是一样的

  1.  
    [root@ecfdc9c636d6 /]# ip address
  2.  
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  3.  
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  4.  
    inet 127.0.0.1/8 scope host lo
  5.  
    valid_lft forever preferred_lft forever
  6.  
    2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
  7.  
    link/ipip 0.0.0.0 brd 0.0.0.0
  8.  
    3: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
  9.  
    link/sit 0.0.0.0 brd 0.0.0.0
  10.  
    8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  11.  
    link/ether …… brd ff:ff:ff:ff:ff:ff link-netnsid 0
  12.  
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
  13.  
    valid_lft forever preferred_lft forever
  14.  
    [root@ecfdc9c636d6 /]# ip route show
  15.  
    default via 172.17.0.1 dev eth0
  16.  
    172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2
  17.  
    [root@ecfdc9c636d6 /]#
学新通

        本机IP为172.17.0.2,网关为172.17.0.1.

        (4)Ping测试

        Windows到WSL宿主机

  1.  
    PS C:\Users\lhyzw> ping 172.23.162.71
  2.  
     
  3.  
    正在 Ping 172.23.162.71 具有 32 字节的数据:
  4.  
    来自 172.23.162.71 的回复: 字节=32 时间<1ms TTL=64
  5.  
    来自 172.23.162.71 的回复: 字节=32 时间<1ms TTL=64
  6.  
    来自 172.23.162.71 的回复: 字节=32 时间<1ms TTL=64
  7.  
    来自 172.23.162.71 的回复: 字节=32 时间<1ms TTL=64
  8.  
     
  9.  
    172.23.162.71 的 Ping 统计信息:
  10.  
    数据包: 已发送 = 4,已接收 = 4,丢失 = 0 (0% 丢失),
  11.  
    往返行程的估计时间(以毫秒为单位):
  12.  
    最短 = 0ms,最长 = 0ms,平均 = 0ms
  13.  
     
  14.  
    PS C:\Users\lhyzw> ping 172.23.160.1
  15.  
     
  16.  
    正在 Ping 172.23.160.1 具有 32 字节的数据:
  17.  
    来自 172.23.160.1 的回复: 字节=32 时间<1ms TTL=64
  18.  
    来自 172.23.160.1 的回复: 字节=32 时间<1ms TTL=64
  19.  
    来自 172.23.160.1 的回复: 字节=32 时间<1ms TTL=64
  20.  
     
  21.  
    172.23.160.1 的 Ping 统计信息:
  22.  
    数据包: 已发送 = 3,已接收 = 3,丢失 = 0 (0% 丢失),
  23.  
    往返行程的估计时间(以毫秒为单位):
  24.  
    最短 = 0ms,最长 = 0ms,平均 = 0ms
学新通

        Ping宿主机与宿主机的网关均没有问题 

        WSL宿主机到容器

  1.  
    pig@LAPTOP-SA9UAFHF:/mnt/c/Users/lhyzw$ ping 172.17.0.1
  2.  
    PING 172.17.0.1 (172.17.0.1) 56(84) bytes of data.
  3.  
    --- 172.17.0.1 ping statistics ---
  4.  
    4 packets transmitted, 0 received, 100% packet loss, time 3115ms
  5.  
     
  6.  
    pig@LAPTOP-SA9UAFHF:/mnt/c/Users/lhyzw$ ping 172.17.0.2
  7.  
    PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
  8.  
    --- 172.17.0.2 ping statistics ---
  9.  
    45 packets transmitted, 0 received, 100% packet loss, time 45789ms
  10.  
     
  11.  
    pig@LAPTOP-SA9UAFHF:/mnt/c/Users/lhyzw$

        这里会发现,实际上从WSL上的Ubuntu,是不可能Ping到内部的容器的 

        Windows到容器

        这就不用试了,因为WSL就连不到容器,Windows更不可能连到

        容器到WSL宿主机

  1.  
    [root@ecfdc9c636d6 /]# ping 172.23.162.71
  2.  
    PING 172.23.162.71 (172.23.162.71) 56(84) bytes of data.
  3.  
    64 bytes from 172.23.162.71: icmp_seq=1 ttl=37 time=1.71 ms
  4.  
    64 bytes from 172.23.162.71: icmp_seq=2 ttl=37 time=2.56 ms
  5.  
    64 bytes from 172.23.162.71: icmp_seq=3 ttl=37 time=1.79 ms

        宿主机到Windows

  1.  
    pig@LAPTOP-SA9UAFHF:/mnt/c/Users/lhyzw$ ping 172.23.160.1
  2.  
    PING 172.23.160.1 (172.23.160.1) 56(84) bytes of data.
  3.  
    64 bytes from 172.23.160.1: icmp_seq=1 ttl=64 time=0.196 ms
  4.  
    64 bytes from 172.23.160.1: icmp_seq=2 ttl=64 time=0.240 ms
  5.  
    --- 172.23.160.1 ping statistics ---
  6.  
    2 packets transmitted, 2 received, 0% packet loss, time 1017ms
  7.  
    rtt min/avg/max/mdev = 0.196/0.218/0.240/0.022 ms
  8.  
     
  9.  
    pig@LAPTOP-SA9UAFHF:/mnt/c/Users/lhyzw$ ping 192.168.1.26
  10.  
    PING 192.168.1.26 (192.168.1.26) 56(84) bytes of data.
  11.  
    64 bytes from 192.168.1.26: icmp_seq=1 ttl=63 time=0.206 ms
  12.  
    64 bytes from 192.168.1.26: icmp_seq=2 ttl=63 time=0.197 ms
  13.  
    64 bytes from 192.168.1.26: icmp_seq=3 ttl=63 time=0.242 ms

         可以看到宿主机确实是可以Ping通WSL网关和Windows的

        容器到Windows

  1.  
    [root@ecfdc9c636d6 /]# ping 172.23.160.1
  2.  
    PING 172.23.160.1 (172.23.160.1) 56(84) bytes of data.
  3.  
    64 bytes from 172.23.160.1: icmp_seq=1 ttl=37 time=1.07 ms
  4.  
    64 bytes from 172.23.160.1: icmp_seq=2 ttl=37 time=2.02 ms
  5.  
    64 bytes from 172.23.160.1: icmp_seq=3 ttl=37 time=1.20 ms
  6.  
    --- 172.23.160.1 ping statistics ---
  7.  
    3 packets transmitted, 3 received, 0% packet loss, time 2002ms
  8.  
    rtt min/avg/max/mdev = 1.070/1.430/2.021/0.421 ms
  9.  
     
  10.  
    [root@ecfdc9c636d6 /]# ping 192.168.1.26
  11.  
    PING 192.168.1.26 (192.168.1.26) 56(84) bytes of data.
  12.  
    64 bytes from 192.168.1.26: icmp_seq=1 ttl=37 time=0.977 ms
  13.  
    64 bytes from 192.168.1.26: icmp_seq=2 ttl=37 time=1.49 ms
  14.  
    64 bytes from 192.168.1.26: icmp_seq=3 ttl=37 time=1.98 ms
  15.  
    --- 192.168.1.26 ping statistics ---
  16.  
    3 packets transmitted, 3 received, 0% packet loss, time 2003ms
  17.  
    rtt min/avg/max/mdev = 0.977/1.481/1.980/0.409 ms
学新通

         容器也可以Ping到WSL的网关,以及Windows主机。

        容器互联

        在WSL下启动多个容器是否能够互联呢?事实证明确实是可以的:

  1.  
    [root@b5cf7a4cf154 /]# ip address
  2.  
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
  3.  
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
  4.  
    inet 127.0.0.1/8 scope host lo
  5.  
    valid_lft forever preferred_lft forever
  6.  
    2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
  7.  
    link/ipip 0.0.0.0 brd 0.0.0.0
  8.  
    3: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
  9.  
    link/sit 0.0.0.0 brd 0.0.0.0
  10.  
    10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  11.  
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
  12.  
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
  13.  
    valid_lft forever preferred_lft forever
  14.  
    [root@b5cf7a4cf154 /]# ping 172.17.0.2
  15.  
    PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
  16.  
    64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.039 ms
  17.  
    64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.064 ms
  18.  
    64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.065 ms
  19.  
    ^C
  20.  
    --- 172.17.0.2 ping statistics ---
  21.  
    3 packets transmitted, 3 received, 0% packet loss, time 2061ms
  22.  
    rtt min/avg/max/mdev = 0.039/0.056/0.065/0.012 ms
学新通

        (5)连通WSL到容器?

        那么是否我们也可以像连通Windows到容器一样,连通WSL到容器呢?这里有一个问题,就是windows不知道如何连通172.17.0.0/16网段,但是windows知道如何连到宿主机,宿主机又知道如何连到172.17.0.0/16,所以我们可以通过宿主机来构建路由通道。但是,WSL上的Ubuntu作为宿主机的情况下,它自己就不知道如何到通172.17.0.0/16网段,还能找谁去?!

        所以,这个坑我们是爬不出去了……

        当然了,Docker官方给出过正确的办法,就是使用--net:host,并-p绑定端口到主机端口上,直接使用主机IP加端口的方式来访问容器。这正是docker基于进程隔离的理念要求我们采用的“正确方式”。

        3.可能的原因

        这是一个很让人抓狂的事。网络上多数说法,是WSL没有docker0这个虚拟器。这个我们在前面也确实看到了。但是如果真的没有适配器,可能连从容器上行到WSL Ubuntu和Windows都不行,容器互联也应该不行。可见这一部分还是有程序在处理的。只是不太清除的是,为啥这个功能只实现了一半——WSL Ubuntu没有172.17.0.1这样一个适配器做网关,但是容器像172.17.0.1发的包确实被处理了;反过来,虽然容器主动发起的通信能够正常的返回,但WSL端主动发起的通信,却找不到172.17.0.1在哪——一个没有适配器的半拉儿网络暗流。

        有空的话可以考虑截包来看看到底发生了什么……

        当然,除了没有docker0,如果你在WSL Ubuntu上执行一下systemctl命令的话……

  1.  
    pig@LAPTOP-SA9UAFHF:/mnt/c/Users/lhyzw$ systemctl
  2.  
    System has not been booted with systemd as init system (PID 1). Can't operate.
  3.  
    Failed to connect to bus: Host is down

        你会发现,这玩意和容器挺像的,都没有启动systemd服务,是一个阉割版的子系统,这也许是真正的原因所在吧~~~

        PS:当然,在WSL Ubuntu下面也可以安装一个替代的systemctl:

  1.  
     git clone https://github.com/DamionGans/ubuntu-wsl2-systemd-script.git
  2.  
     
  3.  
    cd ubuntu-wsl2-systemd-script/
  4.  
     
  5.  
    bash ubuntu-wsl2-systemd-script.sh

        只不过对联网这件事而言,并不会有啥作用。

        四、从虚拟机到(超级大的)容器

        好了,为什么折腾了这么久的什么服务啊、网络啊这样的大坑呢。其实起源于本篇一开头提过的“奇思妙想”——从scratch创建镜像,从镜像/容器创建镜像我们都试过了。能不能从虚拟机创建一个镜像呢?

        答案当然是可以的,因为前面提到过,其实镜像就是一个文件系统,容器不过使用一个通用的核心加载了这个文件系统而已。所以,从虚拟机到容器,只需要把虚拟机系统里面的文件系统打包出来就行了。

        1.全盘压缩虚拟机文件系统

[root@localhost ~]# tar --numeric-owner --exclude=/proc --exclude=/sys --exclude=/mnt --exclude=/var/cache --exclude=/var/log --exclude=/root/share -zcvf  ~/share/centos-stream-8.tar.gz /

        对虚拟机中的CentOS系统——我们前面安装的可是很全的版本,各种工具及包括图形桌面都安装了,所以文件系统不会太小。当然,在tar的时候,可以使用--exclude参数排除一些对系统来说并不重要的目录。比如:

        /proc:因为存储的是内核运行时状态的相关文件,是从内存映射出来的虚拟目录,伪文件系统。docker会使用承载系统的内核进行替代,所以可以不要。

        /sys:Linux内核设备树及文件系统的映射。同样由于被替代,不需要

        /var:日志文件等通常不断增加的变量性文件存放在这里,不需要。但是/var/lib还是不该轻易删除,不知道会不会映像一些已经安装的软件。所以选择性删一下

        /mnt:用户临时挂载的别的文件系统,不需要

        /root/share:我们自己在虚拟机上映射的共享目录,tar的结果会放在这里,不能被循环压缩,排除。

        /tmp:存放临时文件的目录,事实上也不需要,可以考虑排除,不过我没尝试

        /run:系统运行时生成的临时文件系统,重启时会被删除,应该排除,不过我也没有尝试

        我们这里完全是在反docker之道而行之,不管系统里面的东西有用没用全给打包了,这当然是不理智的行为——正确的方法应该是在scratch的基础上,带上busybox等已经压缩得很紧凑的必要工具集,然后根据需要一点一点的添加。

        当然,做实验的话就无所谓了:)          运行完以后,确实好大一个

  1.  
    [root@localhost share]# pwd
  2.  
    /root/share
  3.  
    [root@localhost share]# ls -lh
  4.  
    总用量 2.1G
  5.  
    -rwxrwxrwx. 1 root root 2.1G 11月 10 03:34 centos-stream-8.tar.gz
  6.  
    [root@localhost share]#

可以在rar里看看 

学新通

        有5G那么多…… 。可以看到除了/boot、/etc、/usr、/bar/lib等绝对不能瘦身和不敢瘦身的东西外,其余目录其实所占空间也不算太多,大面还能节省的一眼看去也只有/run和/tmp了。/root下面还有一些桌面系统用的东西,也没有敢删,毕竟一会还想着用一下……。所以真要是想构造生产环境,还是别从虚拟机这头开始搞吧。

        2.向docker导入镜像

  1.  
    [root@localhost ~]# cat share/centos-stream-8.tar.gz |docker import - centos-stream-8:pig01
  2.  
    sha256:3cf07981b4d47f1a90675d3bbcdb7e83e7053daec3f45d1abd1c5e0e3bb26d9e
  3.  
    [root@localhost ~]# docker images
  4.  
    REPOSITORY TAG IMAGE ID CREATED SIZE
  5.  
    centos-stream-8 pig01 3cf07981b4d4 2 minutes ago 5GB
  6.  
    hello-world latest feb5d9fea6a5 13 months ago 13.3kB
  7.  
    [root@localhost ~]#

        很大,导入很慢……。不过这个工作最好在Linux环境下操作。直接在Windows CMD下操作似乎会因为字符编码问题出错。

  1.  
    PS D:\vm\share> cat .\centos-stream-8.tar.gz |docker import - centos-stream-8:pig01
  2.  
    程序“docker.exe”无法运行: 引发类型为“System.OutOfMemoryException”的异常。所在位置 行:1 字符: 31
  3.  
    cat .\centos-stream-8.tar.gz |docker import - centos-stream-8:pig01
  4.  
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~。
  5.  
    所在位置 行:1 字符: 1
  6.  
    cat .\centos-stream-8.tar.gz |docker import - centos-stream-8:pig01
  7.  
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  8.  
    CategoryInfo : ResourceUnavailable: (:) [], ApplicationFailedException
  9.  
    FullyQualifiedErrorId : NativeCommandFailed

        3.确实能用

        然后我们迫不及待的用一下看看,果然是可以的:

  1.  
    [root@localhost ~]# docker run -it centos-stream-8:pig01 bash
  2.  
    [root@c44c3094af96 /]# ls
  3.  
    bin boot dev etc home lib lib64 media opt proc root run sbin srv sys tmp usr var
  4.  
    [root@c44c3094af96 /]# ls root
  5.  
    公共 模板 视频 图片 文档 下载 音乐 桌面 anaconda-ks.cfg initial-setup-ks.cfg
  6.  
    [root@c44c3094af96 /]#

        4.导出以后换到Windows下面看看

        如果需要在Windows下使用,可以从Linux环境下的Docker中导出dockers镜像

  1.  
    [root@localhost ~]# docker save -o share/testcentoimage.tar centos-stream-8:pig01
  2.  
    [root@localhost ~]# ls -lh share
  3.  
    总用量 6.8G
  4.  
    -rwxrwxrwx. 1 root root 2.1G 11月 10 03:34 centos-stream-8.tar.gz
  5.  
    -rwxrwxrwx. 1 root root 4.8G 11月 10 04:02 testcentoimage.tar

        看大小就不一样,所以应当是不能直接使用docker load命令去load那个我们之前打包的2G大小的压缩包的。

  1.  
    D:\VM\share>dir
  2.  
    驱动器 D 中的卷没有标签。
  3.  
    卷的序列号是 0E5B-11E5
  4.  
     
  5.  
    D:\VM\share 的目录
  6.  
     
  7.  
    2022/11/10 17:02 <DIR> .
  8.  
    2022/11/10 17:02 <DIR> ..
  9.  
    2022/11/04 10:39 6,832,413 cascade-server-master.zip
  10.  
    2022/11/10 16:34 2,150,854,714 centos-stream-8.tar.gz
  11.  
    2022/11/04 15:03 32,118,944 mongodb-org-server-6.0.2-1.el8.x86_64.rpm
  12.  
    2022/11/10 17:02 5,093,537,792 testcentoimage.tar
  13.  
    4 个文件 7,283,343,863 字节
  14.  
    2 个目录 3,864,828,567,552 可用字节
  15.  
     
  16.  
    D:\VM\share>docker load -i testcentoimage.tar
  17.  
    4d9db9558c67: Loading layer [==================================================>] 5.094GB/5.094GB
  18.  
    Loaded image: centos-stream-8:pig01
学新通

        嗯,看看命令行的风格都不一样了,就知道我换系统了

学新通

        在docker desktop窗口也能看到。在命令行里先运行一下,这样会比较简单地生成容器,如果在窗口中还需要选择一些环境参数,就不研究了。

学新通

 然后就可以从窗口进去,在docker命令行中使用了:

学新通

 命令行:

学新通

 呃……存在一点UTF-8的问题。先放着不管。

        五、远程桌面

        之所以会搞这么大个镜像,是因为客户希望可以直接操作我们远程集群上的app,而且不希望通过浏览器连接,要通过VPN加远程桌面的方式连接,然后在桌面上使用浏览器连接本地集群……用户就是上帝,虽然我也不知道为啥。不过紧接着就突发奇想,能不能把这东西弄到docker上呢?

        1. 使用xrdp远程桌面

        当然事情还得一步一步做,至少我得先解决在虚拟机上能够使用远程桌面的问题。网上有好多使用xshell、vnc的方案,不过要么是需要购买,要么是配置起来太麻烦,不确定性太多。还在在我一通收罗下,找着一个不错的远程桌面XRDP。这个家伙不仅好安装,而且就连客户端都可以直接使用Windows的远程桌面。

        xrdp需要首先安装epel的repo。

  1.  
    [root@localhost ~]# yum install epel-release
  2.  
    CentOS Stream 8 - AppStream 1.4 MB/s | 25 MB 00:18
  3.  
    CentOS Stream 8 - BaseOS 644 kB/s | 26 MB 00:40
  4.  
    CentOS Stream 8 - Extras 12 kB/s | 18 kB 00:01
  5.  
    CentOS Stream 8 - Extras common packages 5.5 kB/s | 5.2 kB 00:00
  6.  
    依赖关系解决。
  7.  
    ================================================================================
  8.  
    软件包 架构 版本 仓库 大小
  9.  
    ================================================================================
  10.  
    安装:
  11.  
    epel-release noarch 8-11.el8 extras 24 k
  12.  
     
  13.  
    事务概要
  14.  
    ================================================================================
  15.  
    安装 1 软件包
  16.  
     
  17.  
    总下载:24 k
  18.  
    安装大小:35 k
  19.  
    确定吗?[y/N]: y
  20.  
    下载软件包:
  21.  
    epel-release-8-11.el8.noarch.rpm 40 kB/s | 24 kB 00:00
  22.  
    --------------------------------------------------------------------------------
  23.  
    总计 21 kB/s | 24 kB 00:01
  24.  
    CentOS Stream 8 - Extras 1.2 MB/s | 1.6 kB 00:00
  25.  
    导入 GPG 公钥 0x8483C65D:
  26.  
    Userid: "CentOS (CentOS Official Signing Key) <security@centos.org>"
  27.  
    指纹: 99DB 70FA E1D7 CE22 7FB6 4882 05B5 55B3 8483 C65D
  28.  
    来自: /etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial
  29.  
    确定吗?[y/N]: y
  30.  
    导入公钥成功
  31.  
    运行事务检查
  32.  
    事务检查成功。
  33.  
    运行事务测试
  34.  
    事务测试成功。
  35.  
    运行事务
  36.  
    准备中 : 1/1
  37.  
    安装 : epel-release-8-11.el8.noarch 1/1
  38.  
    运行脚本: epel-release-8-11.el8.noarch 1/1
  39.  
    验证 : epel-release-8-11.el8.noarch 1/1
  40.  
     
  41.  
    已安装:
  42.  
    epel-release-8-11.el8.noarch
  43.  
     
  44.  
    完毕!
学新通

        安装xrdp

  1.  
    [root@localhost ~]# yum install xrdp -y
  2.  
    Extra Packages for Enterprise Linux 8 - x86_64 1.7 MB/s | 13 MB 00:07
  3.  
    Extra Packages for Enterprise Linux Modular 8 - x86_64 1.0 MB/s | 733 kB 00:00
  4.  
    上次元数据过期检查:0:00:01 前,执行于 2022年11月11日 星期五 01时28分27秒。
  5.  
    依赖关系解决。
  6.  
    ==================================================================================================================================================
  7.  
    软件包 架构 版本 仓库 大小
  8.  
    ==================================================================================================================================================
  9.  
    安装:
  10.  
    xrdp x86_64 1:0.9.20-1.el8 epel 471 k
  11.  
    安装依赖关系:
  12.  
    imlib2 x86_64 1.4.9-8.el8 epel 222 k
  13.  
    安装弱的依赖:
  14.  
    xrdp-selinux x86_64 1:0.9.20-1.el8 epel 24 k
  15.  
     
  16.  
    事务概要
  17.  
    ==================================================================================================================================================
  18.  
    安装 3 软件包
  19.  
     
  20.  
    总下载:717 k
  21.  
    安装大小:2.8 M
  22.  
    下载软件包:
  23.  
    (1/3): xrdp-selinux-0.9.20-1.el8.x86_64.rpm 184 kB/s | 24 kB 00:00
  24.  
    (2/3): imlib2-1.4.9-8.el8.x86_64.rpm 942 kB/s | 222 kB 00:00
  25.  
    (3/3): xrdp-0.9.20-1.el8.x86_64.rpm 983 kB/s | 471 kB 00:00
  26.  
    --------------------------------------------------------------------------------------------------------------------------------------------------
  27.  
    总计 794 kB/s | 717 kB 00:00
  28.  
    Extra Packages for Enterprise Linux 8 - x86_64 1.6 MB/s | 1.6 kB 00:00
  29.  
    导入 GPG 公钥 0x2F86D6A1:
  30.  
    Userid: "Fedora EPEL (8) <epel@fedoraproject.org>"
  31.  
    指纹: 94E2 79EB 8D8F 25B2 1810 ADF1 21EA 45AB 2F86 D6A1
  32.  
    来自: /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-8
  33.  
    导入公钥成功
  34.  
    运行事务检查
  35.  
    事务检查成功。
  36.  
    运行事务测试
  37.  
    事务测试成功。
  38.  
    运行事务
  39.  
    准备中 : 1/1
  40.  
    安装 : imlib2-1.4.9-8.el8.x86_64 1/3
  41.  
    安装 : xrdp-selinux-1:0.9.20-1.el8.x86_64 2/3
  42.  
    运行脚本: xrdp-selinux-1:0.9.20-1.el8.x86_64 2/3
  43.  
    安装 : xrdp-1:0.9.20-1.el8.x86_64 3/3
  44.  
    运行脚本: xrdp-1:0.9.20-1.el8.x86_64 3/3
  45.  
    验证 : imlib2-1.4.9-8.el8.x86_64 1/3
  46.  
    验证 : xrdp-1:0.9.20-1.el8.x86_64 2/3
  47.  
    验证 : xrdp-selinux-1:0.9.20-1.el8.x86_64 3/3
  48.  
     
  49.  
    已安装:
  50.  
    imlib2-1.4.9-8.el8.x86_64 xrdp-1:0.9.20-1.el8.x86_64 xrdp-selinux-1:0.9.20-1.el8.x86_64
  51.  
     
  52.  
    完毕!
  53.  
    [root@localhost ~]#
学新通

        启动并设置服务

  1.  
    [root@localhost ~]# systemctl start xrdp
  2.  
    [root@localhost ~]# systemctl status xrdp
  3.  
    ● xrdp.service - xrdp daemon
  4.  
    Loaded: loaded (/usr/lib/systemd/system/xrdp.service; disabled; vendor preset: disabled)
  5.  
    Active: active (running) since Fri 2022-11-11 01:29:55 EST; 10s ago
  6.  
    Docs: man:xrdp(8)
  7.  
    man:xrdp.ini(5)
  8.  
    Main PID: 23053 (xrdp)
  9.  
    Tasks: 1 (limit: 23329)
  10.  
    Memory: 1004.0K
  11.  
    CGroup: /system.slice/xrdp.service
  12.  
    └─23053 /usr/sbin/xrdp --nodaemon
  13.  
     
  14.  
    11月 11 01:29:55 localhost.localdomain systemd[1]: Started xrdp daemon.
  15.  
    11月 11 01:29:55 localhost.localdomain xrdp[23053]: [INFO ] starting xrdp with pid 23053
  16.  
    11月 11 01:29:55 localhost.localdomain xrdp[23053]: [INFO ] address [0.0.0.0] port [3389] mode 1
  17.  
    11月 11 01:29:55 localhost.localdomain xrdp[23053]: [INFO ] listening to port 3389 on 0.0.0.0
  18.  
    11月 11 01:29:55 localhost.localdomain xrdp[23053]: [INFO ] xrdp_listen_pp done
  19.  
    [root@localhost ~]# systemctl enable xrdp
  20.  
    Created symlink /etc/systemd/system/multi-user.target.wants/xrdp.service → /usr/lib/systemd/system/xrdp.service.
  21.  
    [root@localhost ~]#
学新通

        停止防火墙。一般来说很早就会干这个事,不过这次我换了个新的虚拟机,把这个忘了,坑了一小会……

  1.  
    [root@localhost ~]# netstat -antpl
  2.  
    Active Internet connections (servers and established)
  3.  
    Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
  4.  
    tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 1/systemd
  5.  
    tcp 0 0 192.168.122.1:53 0.0.0.0:* LISTEN 2129/dnsmasq
  6.  
    tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1241/sshd
  7.  
    tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 1237/cupsd
  8.  
    tcp6 0 0 :::111 :::* LISTEN 1/systemd
  9.  
    tcp6 0 0 ::1:3350 :::* LISTEN 1292/xrdp-sesman
  10.  
    tcp6 0 0 :::22 :::* LISTEN 1241/sshd
  11.  
    tcp6 0 0 ::1:631 :::* LISTEN 1237/cupsd
  12.  
    tcp6 0 0 :::3389 :::* LISTEN 1295/xrdp
  13.  
    [root@localhost ~]# systemctl stop firewalld.service
  14.  
    [root@localhost ~]# systemctl disable firewalld.service
  15.  
    Removed /etc/systemd/system/multi-user.target.wants/firewalld.service.
  16.  
    Removed /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
  17.  
    [root@localhost ~]#
学新通

        安装好了以后,就可以使用Windows的远程桌面连接进行登录。

学新通

        提示证书什么不用管,直接连接就好。但是有一件事需要注意,就是和windows远程桌面一样,不允许一个用户同时登录2次。在windows中,新的用户会把原来的用户挤下来,但是在Linux中,是新的用户挤不进去,闪退……

        我被这个坑了好久,一直在查软件配置的问题,知道半天多以后猛然灵光一闪……学新通

        换了个用户,这样就登进去了

        显示设置也可以更改一下,方便放多个窗口

学新通

         有趣的是,和Windows中不一样的是,如果在远程桌面中关机,不是注销用户,而是直接把主机也关掉了。这个要是用在生产环境中,哪个用户一关机……就相当尴尬了。

        2. 把远程桌面架到Docker上

        下一步该琢磨的,是怎么在dockers中装上远程桌面。

        (1)安装epel和xrdp

        首先是在我们现有的超大镜像上再构造一层,把epel和xrdp装上。

        这个使用Dockerfile文件比较简单的可以做到:

  1.  
    FROM centos-stream-8:pig01
  2.  
    RUN yum install epel-release -y \
  3.  
    && yum install xrdp -y
  4.  
    CMD ["/bin/bash"]
  1.  
    PS D:\vm\share\docker> docker build -t centos-stream-8:pig02 .
  2.  
    [ ] Building 0.4s (2/2) FINISHED
  3.  
    => [internal] load build definition from Dockerfile 0.1s
  4.  
    => => transferring dockerfile: 282B 0.0s
  5.  
    => [internal] load .dockerignore 0.1s
  6.  
    => => transferring context: 2B 0.0s
  7.  
    failed to solve with frontend dockerfile.v0: failed to create LLB definition: dockerfile parse error line 3: unknown instruction: &&
  8.  
    [ ] Building 451.9s (5/6)
  9.  
    => [internal] load build definition from Dockerfile 0.1s
  10.  
    => => transferring dockerfile: 281B 0.0s
  11.  
    => [internal] load .dockerignore 0.0s
  12.  
    => => transferring context: 2B 0.0s
  13.  
    => [internal] load metadata for docker.io/library/centos-stream-8:pig01 0.0s
  14.  
    => [1/3] FROM docker.io/library/centos-stream-8:pig01 0.1s
  15.  
    => [2/3] RUN yum install epel-release -y && yum install xrdp -y 212.3s
  16.  
    => [3/3] RUN source /etc/sysconfig/xrdp && /usr/sbin/xrdp-sesman $SESMAN_OPTIONS --nodaemon && /usr/sbin/xrdp $XRDP_OPTIONS --nodaemon 239.1s
学新通

        (2)启动xrdp服务

        xrdp的服务配置如下所示:

  1.  
    [root@localhost system]# cat xrdp-sesman.service 
  2.  
    [Unit]
  3.  
    Description=xrdp session manager
  4.  
    Documentation=man:xrdp-sesman(8) man:sesman.ini(5)
  5.  
    Wants=network-online.target nss-lookup.target nss-user-lookup.target
  6.  
    After=network-online.target nss-lookup.target nss-user-lookup.target
  7.  
    StopWhenUnneeded=true
  8.  
    BindsTo=xrdp.service
  9.  
     
  10.  
    [Service]
  11.  
    EnvironmentFile=/etc/sysconfig/xrdp
  12.  
    ExecStart=/usr/sbin/xrdp-sesman $SESMAN_OPTIONS --nodaemon
  13.  
     
  14.  
    [Install]
  15.  
    WantedBy=multi-user.target
  16.  
    [root@localhost system]# cat xrdp.service 
  17.  
    [Unit]
  18.  
    Description=xrdp daemon
  19.  
    Documentation=man:xrdp(8) man:xrdp.ini(5)
  20.  
    Requires=xrdp-sesman.service
  21.  
    After=xrdp-sesman.service
  22.  
     
  23.  
    [Service]
  24.  
    EnvironmentFile=/etc/sysconfig/xrdp
  25.  
    ExecStart=/usr/sbin/xrdp $XRDP_OPTIONS --nodaemon
  26.  
     
  27.  
    [Install]
  28.  
    WantedBy=multi-user.target
  29.  
    [root@localhost system]
学新通

        可以看到,xrdp还依赖于xrdp-sesman服务,并且这些服务都需要再ns-lookup/nss-user-lookup等systemd的核心组成模块启动后才能正常运行。所以在启动这些服务前,还需要把systemd启动起来。

        为什么我们没有在Dockerfile里面使用RUN来启动这几个服务呢?因为前面说过,不管是手撸还是使用RUN,本质上都是单线程的在启动程序,一旦碰见一个不支持-d参数按照daemon模式启动的,就会挂住。事实上如果都放在RUN里面,构造镜像的时候就会挂在那里不动了。

        好在如果手撸,可以采取exec的方式,只要容器还在运行,就多开一个交互式bash挂进去,如此反复,可以将所有的服务都启动起来。

        但是这里还有一个问题,就是systemd,xrdp在systemd没有启动的情况下,是不能正常工作的。所以我们最终还是得回到前面说的/sbin/init大法,在docker启动的时候指定启动/sbin/init,强行把systemd启动起来。

        另外,如前所述的网络问题,我们还需要将docker的3350(xrdp-sesman)和3389(xrdp)端口和主机绑定:

  1.  
    PS D:\vm\share\docker> docker run -it -p 3350:3350 -p 3389:3389 --name pig02 --privileged centos-stream-8:pig02 /sbin/init
  2.  
     
  3.  
    Welcome to CentOS Stream 8!
  4.  
     
  5.  
    [ OK ] Created slice User and Session Slice.
  6.  
    [ OK ] Created slice system-getty.slice.
  7.  
    [ OK ] Listening on initctl Compatibility Named Pipe.
  8.  
    [ OK ] Created slice system-sshd\x2dkeygen.slice.
  9.  
    [ OK ] Listening on udev Kernel Socket.
  10.  
    [ OK ] Reached target Login Prompts.
  11.  
    [ OK ] Set up automount Arbitrary Executable File Formats File System Automount Point.
  12.  
    [ OK ] Listening on Journal Socket.
  13.  
    Starting Load Kernel Modules...
  14.  
    Starting Read and set NIS domainname from /etc/sysconfig/network...
  15.  
    Starting Remount Root and Kernel File Systems...
  16.  
    Mounting Kernel Debug File System...
  17.  
    Starting Setup Virtual Console...
  18.  
    [ OK ] Listening on Journal Socket (/dev/log).
  19.  
    Starting Journal Service...
  20.  
    [ OK ] Created slice Virtual Machine and Container Slice.
  21.  
    Mounting Huge Pages File System...
  22.  
    [ OK ] Listening on udev Control Socket.
  23.  
    Starting udev Coldplug all Devices...
  24.  
    [ OK ] Started Forward Password Requests to Wall Directory Watch.
  25.  
    [ OK ] Listening on Device-mapper event daemon FIFOs.
  26.  
    Starting Monitoring of LVM2 mirrors, snapshots etc. using dmeventd or progress polling...
  27.  
    [ OK ] Listening on Process Core Dump Socket.
  28.  
    [ OK ] Listening on RPCbind Server Activation Socket.
  29.  
    [ OK ] Reached target RPC Port Mapper.
  30.  
    [ OK ] Listening on LVM2 poll daemon socket.
  31.  
    [ OK ] Reached target Slices.
  32.  
    [ OK ] Started Read and set NIS domainname from /etc/sysconfig/network.
  33.  
    [ OK ] Mounted Kernel Debug File System.
  34.  
    [ OK ] Mounted Huge Pages File System.
  35.  
    [FAILED] Failed to start Load Kernel Modules.
  36.  
    See 'systemctl status systemd-modules-load.service' for details.
  37.  
    [ OK ] Started Remount Root and Kernel File Systems.
  38.  
    Starting Load/Save Random Seed...
  39.  
    Starting Create Static Device Nodes in /dev...
  40.  
    Mounting FUSE Control File System...
  41.  
    Starting Apply Kernel Variables...
  42.  
    [ OK ] Started Load/Save Random Seed.
  43.  
    [ OK ] Mounted FUSE Control File System.
  44.  
    [ OK ] Started Apply Kernel Variables.
  45.  
    [ OK ] Started Create Static Device Nodes in /dev.
  46.  
    Starting udev Kernel Device Manager...
  47.  
    [ OK ] Started Journal Service.
  48.  
    Starting Flush Journal to Persistent Storage...
  49.  
    [ OK ] Started Setup Virtual Console.
  50.  
    [ OK ] Started udev Kernel Device Manager.
  51.  
    [ OK ] Started udev Coldplug all Devices.
  52.  
    Starting udev Wait for Complete Device Initialization...
  53.  
    Starting Show Plymouth Boot Screen...
  54.  
    [ OK ] Started Flush Journal to Persistent Storage.
  55.  
    [ OK ] Started Show Plymouth Boot Screen.
  56.  
    [ OK ] Started Forward Password Requests to Plymouth Directory Watch.
  57.  
    [ OK ] Reached target Local Encrypted Volumes.
  58.  
    [ OK ] Started Monitoring of LVM2 mirrors, snapshots etc. using dmeventd or progress polling.
  59.  
    [ OK ] Started udev Wait for Complete Device Initialization.
  60.  
    [ OK ] Reached target Local File Systems (Pre).
  61.  
    [ TIME ] Timed out waiting for device dev-mapper-cs\x2dswap.device.
  62.  
    [DEPEND] Dependency failed for /dev/mapper/cs-swap.
  63.  
    [DEPEND] Dependency failed for Swap.
  64.  
    [ TIME ] Timed out waiting for device dev-mapper-cs\x2dhome.device.
  65.  
    [DEPEND] Dependency failed for /home.
  66.  
    [DEPEND] Dependency failed for Local File Systems.
  67.  
    [DEPEND] Dependency failed for Mark the need to relabel after reboot.
  68.  
    [ TIME ] Timed out waiting for device dev-disk-by\x2duuid-074b94e8\x2dbc92\x2d4781\x2d8880\x2d50e42d4aaeea.device.
  69.  
    [DEPEND] Dependency failed for /boot.
  70.  
    [ OK ] Reached target Timers.
  71.  
    [ OK ] Reached target User and Group Name Lookups.
  72.  
    [ OK ] Reached target Network (Pre).
  73.  
    [ OK ] Reached target Paths.
  74.  
    [ OK ] Reached target Network.
  75.  
    [ OK ] Reached target Network is Online.
  76.  
    Starting Notify NFS peers of a restart...
  77.  
    Starting Logout off all iSCSI sessions on shutdown...
  78.  
    [ OK ] Started Emergency Shell.
  79.  
    Starting Tell Plymouth To Write Out Runtime Data...
  80.  
    [ OK ] Reached target Emergency Mode.
  81.  
    Starting Create Volatile Files and Directories...
  82.  
    [ OK ] Reached target Sockets.
  83.  
    [ OK ] Started Notify NFS peers of a restart.
  84.  
    [ OK ] Started Logout off all iSCSI sessions on shutdown.
  85.  
    [ OK ] Started Tell Plymouth To Write Out Runtime Data.
  86.  
    [ OK ] Started Create Volatile Files and Directories.
  87.  
    Mounting RPC Pipe File System...
  88.  
    Starting Security Auditing Service...
  89.  
    Starting RPC Bind...
  90.  
    [ OK ] Mounted RPC Pipe File System.
  91.  
    [ OK ] Reached target rpc_pipefs.target.
  92.  
    [ OK ] Reached target NFS client services.
  93.  
    [ OK ] Reached target Remote File Systems (Pre).
  94.  
    [ OK ] Reached target Remote File Systems.
  95.  
    [FAILED] Failed to start Security Auditing Service.
  96.  
    See 'systemctl status auditd.service' for details.
  97.  
    Starting Update UTMP about System Boot/Shutdown...
  98.  
    [ OK ] Started RPC Bind.
  99.  
    [ OK ] Started Update UTMP about System Boot/Shutdown.
  100.  
    Starting Update UTMP about System Runlevel Changes...
  101.  
    [ OK ] Started Update UTMP about System Runlevel Changes.
  102.  
    You are in emergency mode. After logging in, type "journalctl -xb" to view
  103.  
    system logs, "systemctl reboot" to reboot, "systemctl default" or "exit"
  104.  
    to boot into default mode.
  105.  
    ?? root ?????
  106.  
    (?? Control-D ???):
  107.  
    ?????
学新通

        启动到中间(看具体如何镜像的系统而定),我这个会报错,输入一下密码就进去了。

        如果没有替换systemctl,直接使用系统原有的systemctl启动xrdp服务还是会存在问题。所以我们开了几个交互式界面进行手撸:

        第一个:

  1.  
    PS D:\vm\share\docker> docker exec -it pig02 bash
  2.  
    [root@d84fc5536215 /]# /usr/sbin/xrdp-sesman --nodaemon

        第二个:

  1.  
    PS D:\vm\share\docker> docker exec -it pig02 bash
  2.  
    [root@d84fc5536215 /]# /usr/sbin/xrdp --nodaemon

         再开一个看看端口是否打开了:

  1.  
    C:\Users\dell>docker port pig02
  2.  
    3350/tcp -> 0.0.0.0:3350
  3.  
    3389/tcp -> 0.0.0.0:3389

          (3)连接测试      

        最终,我们可以成功的启动xrdp服务,并且使用远程桌面连接也可以访问容器中的服务了。当然,在绑定主机端口时,所谓的主机实际上是wsl上的那个Ubuntu子系统,所以使用IP地址的时候不要弄错了。

学新通

 学新通

        登录的过程中,如果是手撸的服务,那个进程会不断的输出log来。

        但最终的结果,还是闪退……但是对比虚拟机上成功的访问,和docker上不成功的访问,2者几乎没有区别,xrdp也没有报错(如果服务启动不正确的话,会有大量的[ERROR]和[WARNING]):

  1.  
    [root@925f040afc94 /]# /usr/sbin/xrdp-sesman --nodaemon
  2.  
    xauth: file .Xauthority does not exist
  3.  
     
  4.  
    Xvnc TigerVNC 1.12.0 - built Aug 27 2022 13:07:52
  5.  
    Copyright (C) 1999-2021 TigerVNC Team and many others (see README.rst)
  6.  
    See https://www.tigervnc.org for information on TigerVNC.
  7.  
    Underlying X server release 12011000, The X.Org Foundation
  8.  
     
  9.  
     
  10.  
    Mon Dec 5 02:10:45 2022
  11.  
    vncext: VNC extension running!
  12.  
    vncext: Listening for VNC connections on local interface(s), port 5910
  13.  
    vncext: created VNC server for screen 0
  14.  
    Connections: accepted: 127.0.0.1::56400
  15.  
    SConnection: Client needs protocol version 3.3
  16.  
    VNCSConnST: Server default pixel format depth 32 (32bpp) little-endian rgb
  17.  
    max 255,255,255 shift 16,8,0
  18.  
    Global configuration:
  19.  
    UseUnixSocket (derived): true
  20.  
     
  21.  
    Security configuration:
  22.  
    RestrictOutboundClipboard: none
  23.  
    RestrictInboundClipboard: none
  24.  
     
  25.  
    Chansrv configuration:
  26.  
    EnableFuseMount true
  27.  
    FuseMountName: thinclient_drives
  28.  
    FileMask: 077
  29.  
    Nautilus 3 Flist Format: false
  30.  
    chansrv::main: using log file [/home/pig/.local/share/xrdp/xrdp-chansrv.10.log]
  31.  
    VNCSConnST: Client pixel format depth 24 (32bpp) little-endian rgb888
  32.  
     
  33.  
    Mon Dec 5 02:10:46 2022
  34.  
    VNCSConnST: closing 127.0.0.1::56400: Server shutdown
  35.  
    EncodeManager: Framebuffer updates: 1
  36.  
    EncodeManager: Raw:
  37.  
    EncodeManager: Solid: 136 rects, 8.2944 Mpixels
  38.  
    EncodeManager: 31.6422 MiB (1:1 ratio)
  39.  
    EncodeManager: Total: 136 rects, 8.2944 Mpixels
  40.  
    EncodeManager: 31.6422 MiB (1:1 ratio)
  41.  
    ComparingUpdateTracker: 0 pixels in / 0 pixels out
  42.  
    ComparingUpdateTracker: (1:-nan ratio)
学新通

如果成功(比如在VMware上),应该是这样的

  1.  
    [root@localhost ~]# /usr/sbin/xrdp-sesman --nodaemon
  2.  
     
  3.  
    Xvnc TigerVNC 1.12.0 - built Aug 27 2022 13:07:52
  4.  
    Copyright (C) 1999-2021 TigerVNC Team and many others (see README.rst)
  5.  
    See https://www.tigervnc.org for information on TigerVNC.
  6.  
    Underlying X server release 12011000, The X.Org Foundation
  7.  
     
  8.  
     
  9.  
    Mon Dec 5 02:51:29 2022
  10.  
    vncext: VNC extension running!
  11.  
    vncext: Listening for VNC connections on local interface(s), port 5911
  12.  
    vncext: created VNC server for screen 0
  13.  
    Global configuration:
  14.  
    UseUnixSocket (derived): true
  15.  
     
  16.  
    Security configuration:
  17.  
    RestrictOutboundClipboard: none
  18.  
    RestrictInboundClipboard: none
  19.  
     
  20.  
    Chansrv configuration:
  21.  
    EnableFuseMount true
  22.  
    FuseMountName: thinclient_drives
  23.  
    FileMask: 077
  24.  
    Nautilus 3 Flist Format: false
  25.  
    chansrv::main: using log file [/home/pig/.local/share/xrdp/xrdp-chansrv.11.log]
  26.  
    Connections: accepted: 127.0.0.1::32882
  27.  
    SConnection: Client needs protocol version 3.3
  28.  
    VNCSConnST: Server default pixel format depth 32 (32bpp) little-endian rgb
  29.  
    max 255,255,255 shift 16,8,0
  30.  
    VNCSConnST: Client pixel format depth 24 (32bpp) little-endian rgb888
  31.  
     
  32.  
    Mon Dec 5 02:51:33 2022
  33.  
    ComparingUpdateTracker: 0 pixels in / 0 pixels out
  34.  
    ComparingUpdateTracker: (1:-nan ratio)
  35.  
    VNCSConnST: FramebufferUpdateRequest 3840x2160 at 0,0 exceeds framebuffer
  36.  
    1280x1024
学新通

        具体出了啥问题我就不知道了,只有最后那一步FramebufferUpdateRequest没有成功。

        3.可能的原因      

        (1)宿主机和容器同操作系统的实验

        接下来我突发奇想,如果就在VMware上的centos-stream-8中安装docker,并就在这个docker中运行一个同样版本的centos-stream-8的镜像,尽可能给它们一样的环境,xrdp是否能正常呢?结果还真是——又前进了一小步:在pig02从默认的/sbin/init启动时,居然整个主机都进入了交互式界面的欢迎界面:

学新通

         当然,最后仍然不出意外的进入了emergency模式。

        (2)docker的那个scratch内核到底是什么?

        由于在不同的宿主机下,尝试远程登陆交互式界面得到的结果不一样,所以我多做了一步实验,看看不同宿主机下的容器的内核到底是什么:

        WSL下:

        宿主机,也就WSL下的Ubuntu子系统

学新通

         容器,使用的还是我们造的那个centos-strem-8的超大镜像:

学新通

         VMware Centos-Stream-8下:

        宿主机,那个超级大镜像的母体:

学新通

         容器,那个超级大镜像载入后得到的容器:

学新通

         可见,容器所使用的内核——也就是scratch所对应的内核,其实就是docker宿主机上那个Linux系统的内核——如果希望容器工作得更稳定一些,考虑宿主机和容器同内核看起来比较靠谱一点。

        这正好强有力的说明了一个问题,对于基于操作系统虚拟化的Docker来说,进程隔离才是它真正的主业。

        关于远程docker交互式界面这个事,也许仔细地去构建支持xrdp的服务树还是有可能办到的。鉴于我还没有打算去研究xrdp,也没有功夫去回溯systemd的服务树。在一顿磕磕绊绊下能走到这一步也还算不错,倒在革命的最后一步虽然心有不甘也只能就此罢了。

        六、解决方案

        当然,如果就是要在容器下使用远程桌面的话,用一用线程的镜像也不错,使用docker search xrdp,可以找到可用的镜像,比如danchitnis/xrdp的若干镜像,按照其加载说明加载(主要事docker run要在尾巴后面添加 用户 口令 sudo权限开关3个参数),就可以使用windows的远程桌面访问了。但是多数容器使用的都是轻量级的桌面系统xfce,我大致查看了一下,在xrdp方面和我们前面的做法并无二致,但就是搞不同,不知为何。当然,网上也有用VNC装成功的,可以参考在Docker搭建centos7远程桌面环境 - 腾讯云开发者社区-腾讯云 (tencent.com)

        然后我们也参考这种办法,看看能不能直接从较小的镜像开始安装GNOME,只不过后面改成xrdp,事实证明,还真成功了……看起来还真是直接从虚拟机镜像存在某个方面的配置问题。也不想深究了。能用就好:

         1. 启动基础容器

        首先,是启动基于centos:centos7官方镜像的容器。启动过程中,需要绑定端口,并且从/sbin/init进入,因为后面我们需要使用一下systemctl。下面的-it也可以改成-d,免得看见不断初始化失败的某些组件心烦:)

C:\Users\lhyzw>docker run -it --name pig --privileged -p 3389:3389 centos:centos7 sbin/init

        然后,使用exec进入该容器

C:\Users\lhyzw>docker exec -it pig bash

        2. 安装GNOME

        首先需要安装epel-release,然后可以使用yum grouplist命令查看可用软件包。GNOME属于可用环境,可以看到xfce也在可用软件包中。

  1.  
    [root@dbd139d35b50 /]# yum install epel-release -y
  2.  
    ……………………
  3.  
    ……………………
  4.  
     
  5.  
    Installed:
  6.  
    epel-release.noarch 0:7-11
  7.  
    Complete!
  8.  
    [root@dbd139d35b50 /]# yum grouplist
  9.  
    ……………………
  10.  
    Available Environment Groups:
  11.  
    Minimal Install
  12.  
    Compute Node
  13.  
    Infrastructure Server
  14.  
    File and Print Server
  15.  
    Cinnamon Desktop
  16.  
    MATE Desktop
  17.  
    Basic Web Server
  18.  
    Virtualization Host
  19.  
    Server with GUI
  20.  
    GNOME Desktop
  21.  
    KDE Plasma Workspaces
  22.  
    Development and Creative Workstation
  23.  
    Available Groups:
  24.  
    Cinnamon
  25.  
    Compatibility Libraries
  26.  
    Console Internet Tools
  27.  
    Development Tools
  28.  
    Educational Software
  29.  
    Electronic Lab
  30.  
    Fedora Packager
  31.  
    General Purpose Desktop
  32.  
    Graphical Administration Tools
  33.  
    Haskell
  34.  
    LXQt Desktop
  35.  
    Legacy UNIX Compatibility
  36.  
    MATE
  37.  
    Milkymist
  38.  
    Scientific Support
  39.  
    Security Tools
  40.  
    Smart Card Support
  41.  
    System Administration Tools
  42.  
    System Management
  43.  
    TurboGears application framework
  44.  
    Xfce
  45.  
    Done
学新通

        然后使用yun groupinstall命令安装GNOME Desktop,800多个组件,等着就行。

  1.  
    [root@dbd139d35b50 /]# yum groupinstall GNOME Desktop -y
  2.  
    Loaded plugins: fastestmirror, ovl
  3.  
    There is no installed groups file.
  4.  
    Maybe run: yum groups mark convert (see man yum)
  5.  
    Loading mirror speeds from cached hostfile
  6.  
    * base: mirrors.njupt.edu.cn
  7.  
    * epel: mirrors.tuna.tsinghua.edu.cn
  8.  
    * extras: mirrors.neusoft.edu.cn
  9.  
    * updates: mirrors.neusoft.edu.cn
  10.  
    Warning: group Desktop does not exist.
  11.  
    Resolving Dependencies
  12.  
    --> Running transaction check
  13.  
    ---> Package NetworkManager-libreswan-gnome.x86_64 0:1.2.4-2.el7 will be installed
  14.  
    --> Processing Dependency: NetworkManager-libreswan(x86-64) = 1.2.4-2.el7 for package: NetworkManager-libreswan-gnome-1.2.4-2.el7.x86_64
  15.  
    --> Processing Dependency: libnma.so.0(libnma_1_2_0)(64bit) for package: NetworkManager-libreswan-gnome-1.2.4-2.el7.x86_64
  16.  
    --> Processing Dependency: libnm.so.0(libnm_1_2_0)(64bit) for package: NetworkManager-libreswan-gnome-1.2.4-2.el7.x86_64
  17.  
    --> Processing Dependency: libnm.so.0(libnm_1_0_0)(64bit) for package: NetworkManager-libreswan-gnome-1.2.4-2.el7.x86_64
  18.  
    …………………………
学新通

         3. 安装xrdp

        同上,不赘述

[root@dbd139d35b50 /]# yum install xrdp -y

        4.配置默认启动模式

        由于官方默认镜像是以命令行方式启动的,需要改为默认以图形方式启动:

  1.  
    [root@dbd139d35b50 /]# systemctl get-default
  2.  
    multi-user.target
  3.  
    [root@dbd139d35b50 /]# systemctl set-default graphical.target
  4.  
    Removed symlink /etc/systemd/system/default.target.
  5.  
    Created symlink from /etc/systemd/system/default.target to /usr/lib/systemd/system/graphical.target.

        可以看到,实际systemctl的作用是更改了一下软链接,这个使用ln命令也能做到,所以如果要自己构建镜像,使用RUN ln ……构建链接就好,就不要求助于systemctl了。

        5. 增加用户名密码

        同上,使用root就行。当然如果需要增加其它用户也可以,不赘述。

  1.  
    [root@dbd139d35b50 sbin]# whoami
  2.  
    root
  3.  
    [root@dbd139d35b50 sbin]# passwd
  4.  
    Changing password for user root.
  5.  
    New password:
  6.  
    Retype new password:

        6. 启动xrdp

        简单一点,直接整命令行

[root@dbd139d35b50 sbin]# xrdp-sesman && xrdp

        由于没有加--no-daemon参数,所以这个执行完就会跳出来,但是监听的后台进程仍然在,不用担心。

        7. WSL中查看

        进入WSL中的Ubuntu子系统查看:

  1.  
    pig@LAPTOP-SA9UAFHF:/mnt/f/VM/share$ netstat -lntp
  2.  
    (Not all processes could be identified, non-owned process info
  3.  
    will not be shown, you would have to be root to see it all.)
  4.  
    Active Internet connections (only servers)
  5.  
    Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
  6.  
    tcp6 0 0 :::3389 :::* LISTEN -
  7.  
    pig@LAPTOP-SA9UAFHF:/mnt/f/VM/share$ ifconfig
  8.  
    eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
  9.  
    inet 172.27.99.221 netmask 255.255.240.0 broadcast 172.27.111.255
  10.  
    inet6 fe80::215:5dff:fe5e:831e prefixlen 64 scopeid 0x20<link>
  11.  
    ether …… txqueuelen 1000 (Ethernet)
  12.  
    RX packets 3704 bytes 416639 (416.6 KB)
  13.  
    RX errors 0 dropped 0 overruns 0 frame 0
  14.  
    TX packets 3510 bytes 8540060 (8.5 MB)
  15.  
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
  16.  
     
  17.  
    lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
  18.  
    inet 127.0.0.1 netmask 255.0.0.0
  19.  
    inet6 ::1 prefixlen 128 scopeid 0x10<host>
  20.  
    loop txqueuelen 1000 (Local Loopback)
  21.  
    RX packets 0 bytes 0 (0.0 B)
  22.  
    RX errors 0 dropped 0 overruns 0 frame 0
  23.  
    TX packets 0 bytes 0 (0.0 B)
  24.  
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
学新通

        主要是确认远程桌面要连接的IP,这是再连接,会发现非常顺利的成功了:

学新通

        七、结论

        结论就是重要的事情说三遍:docker不是虚拟机!docker不是虚拟机!docker不是虚拟机!

        所以,无可奈何的最后结论——反过来也算我扣题了——“搬到Docker上?”,为什么我一早要加个问好来着?重要的还在于我们应该正确的认识docker,这只是个进程隔离的工具,其真正的运行基础核心其实在WSL的子系统上,我们所谓的镜像对docker来说,只是一些文件,如果在核心上能转起来就转起来了,如果支持不到位,分分钟撂挑子也是说来就来的。所以,用好Docker关键还在于认识Docker。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgabjif
系列文章
更多 icon
同类精品
更多 icon
继续加载