·⼀、Namespace
1、概念
Namespace 是实现 Linux 资源隔离的核⼼技术,实现了 6 项资源隔
离,包括主机名、⽤户权限、⽂件系统、⽹络、进程号、进程通
信。
2、作⽤
1. 实现资源隔离:通过使⽤Linux的Namespaces技术,Docker可
以在容器中创建独⽴的进程、⽂件系统、⽹络等环境。
2. 提⾼安全性:使⽤namespace可以实现不同⽤户或者不同进程
之间的隔离,防⽌相互⼲扰和攻击。
3. 实现资源的限制和优化。
4. 构建多租户系统:通过namespace可以构建多租户系统,允许
多个⽤户或多个团队共享主机资源,但彼此之间的数据和权限是
隔离的,保证数据安全和系统稳定性。
3、资源隔离项
1. cgroup:该 namespace 可单独管理⾃⼰的 cgroup,隐藏了进
程所属的控制组身份。
2. ipc:隔离 IPC,⽐如共享内存、信息量等。3. network:隔离⽹络资源,包括⽹络协议栈、⽹络设备、路由
表、防⽕墙、端⼝等。
4. mount:隔离挂载信息,拥有独⽴的⽬录层次。
5. pid:隔离进程号,使 namespace 中的进程 PID 单独编号。
6. time:隔离启动时间点信息和单调时间。
7. user:隔离⽤户管理权限机制(UID/GID),使 namespace 更
安全。
8. uts:隔离主机信息,包括主机名、NIS domain name。
⼆、CGroup
1、概念
cgroup 是 Linux 内核提供的⼀种机制,该机制可以根据特定的⾏
为,将⼀系列任务及⼦任务整合或分隔到按资源划分等级的不同的
组内,为系统资源管理提供⼀个统⼀的框架。
cgroup可以限制被 namespace 隔离起来的资源,还可以为资源设置
权重、计算使⽤量、控制进程启停。
task 任务:cgroups 的属于中,task就表示系统的⼀个进程,在计
算机中的每⼀个进程都叫⼀个 task,task ⼀般使⽤PID进程表示。2、特点
1. cgroups 的 API 以⼀个伪⽂件系统的⽅式实现,即⽤户可以通
过⽂件操作实现 cgroups 的组织管理。
2. cgroups 的组织管理操作单元可以细粒度到线程级别,⽤户态代
码也可以针对系统分配的资源创建和销毁 cgroups,从⽽实现资
源再分配和管理。
3. 所有资源管理的功能都以“subsystem (⼦系统)”的⽅式实现,接
⼝统⼀。
4. ⼦进程创建之初与其⽗进程处于同⼀个 cgroups 的控制组。本
质上来说,cgroups 是内核附加在程序上的⼀系列钩⼦
(hooks),通过程序运⾏时对资源的调度触发相应的钩⼦以达到
资源追踪和限制的⽬的。
3、⽬的
1. 为不同⽤户层⾯的资源管理,提供⼀个统⼀化的接⼝
2. 单个进程的资源控制到操作系统层⾯的虚拟化
4、作⽤
1. 资源限制(Resource Limitation):cgroups 可以对进程组使⽤
的资源总额进⾏限制。如设定应⽤运⾏时使⽤内存的上限,⼀旦
超过这个配额就发出 OOM (Out of Memory) 。
2. 优先级分配(Prioritization):通过分配的 CPU 时间⽚数量及硬
盘 IO 带宽⼤⼩,实际上就相当于控制了进程运⾏的优先级。3. 资源统计 (Accounting):cgroups 可以统计系统的资源使⽤
量,如 CPU 使⽤时⻓、内存⽤量等等,这个功能⾮常适⽤于计
费。
4. 进程控制(Control):cgroups 可以对进程组执⾏挂起、恢复等
操作。
三、Chroot
1、概念
chroot 是在 Linux 系统中的⼀种操作,它可以改变正在运作的软件
进程及其⼦进程的外显根⽬录。
2、作⽤
1. 增加了系统的安全性,限制了⽤户的权⼒
2. 1. 在经过 chroot 之后,在新根下将访问不到旧系统的根⽬录
结构和⽂件,这样就增强了系统的安全性。⼀般会在⽤户登
录前应⽤ chroot,把⽤户的访问能⼒控制在⼀定的范围之
内。
3. 建⽴⼀个与原系统隔离的系统⽬录结构,⽅便⽤户的开发
4. 1. 使⽤ chroot 后,系统读取的是新根下的⽬录和⽂件,这是
⼀个与原系统根下⽂件不相关的⽬录结构。在这个新的环境
中,可以⽤来测试软件的静态编译以及⼀些与系统不相关的
独⽴开发。5. 切换系统的根⽬录位置,引导 Linux 系统启动以及急救系统等
6. 1. chroot 的作⽤就是切换系统的根位置,⽽这个作⽤最为明显
的是在系统初始引导磁盘的处理过程中使⽤,从初始 RAM
磁盘(initrd)切换系统的根位置并执⾏真正的 init。
四、虚拟化状态
1、完全解耦状态
完全解耦虚拟化状态就是为每个软件提供⼀个独⽴的运⾏环境。这
个环境在 hypervisor 层实现硬件的物理划分,并在每个划分的空间
内安装⼀个操作系统,然后在这个操作系统上运⾏想要的软件。2、半解耦状态
在同⼀个环境下可以同时运⾏两个相同的软件,分担软件服务器的
压⼒。这种状态下,所有东⻄都是以软连接的形式创建的,甚⾄包
括内核。⽽且不会改变内核的情况下放进去,为了兼容不同的操作
系统。
3、解耦和半解耦的区别
解耦是直接从硬件上⾯进⾏隔离的,在⼀个单独的系统中运⾏项
⽬。
半解耦运⾏在相对来说不是独⽴的容器⾥,相同的资源仪器使
⽤,以软链接的形式同步到容器中,需要不同的资源时,再单独
下载。
五、namespace:命名空间五、namespace:命名空间
1、查看 apache 的 namespace
[root@iZbp ~]# yum -y install httpd
[root@iZbp ~]# systemctl start httpd.service
[root@iZbp ~]# netstat -anpt |grep httpd
tcp6 0 0 :::80 :::*
LISTEN 2578447/httpd
[root@iZbp ~]# pidof httpd #⽤于查找httpd(指定服
务)的进程ID,包括主进程和其⼦进程
2578451 2578450 2578449 2578448 2578447
[root@iZbp ~]# cd /proc/2578447/ #进⼊到该服务进程⽬
录下
[root@iZbp 2578447]# ll ns #查看Apache服务的
namespace
total 0
lrwxrwxrwx 1 root root 0 Dec 5 20:35 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 ipc -> 'ipc:
[4026531839]'
lrwxrwxrwx 1 root root 0 Dec 5 20:31 mnt -> 'mnt:
[4026532268]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 net -> 'net:
[4026531992]'2、查看 pid=2 的 namespace
lrwxrwxrwx 1 root root 0 Dec 5 20:31 pid -> 'pid:
[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:31 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 uts -> 'uts:
[4026531838]'3、查看容器是否与 nginx 进⾏隔离
[root@doc 43866]# ls -l /proc/2/ns
总⽤量 0
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00 ipc ->
'ipc:[4026531839]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00 mnt ->
'mnt:[4026531840]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00 net ->
'net:[4026531992]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00 pid ->
'pid:[4026531836]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00 time ->
'time:[4026531834]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00 user ->
'user:[4026531837]'
lrwxrwxrwx. 1 root root 0 12⽉ 11 17:00 uts ->
'uts:[4026531838]'
[root@iZbp ~]# ps #此时的bash是当前系统的进程号 PID TTY TIME CMD
2646243 pts/0 00:00:00 bash
2665910 pts/0 00:00:00 ps
[root@iZbp ~]# docker run -itd --name test
centos:7 /bin/bash #运⾏docker容器
1af03b3055f728022d6a5acd51869e4982f3d13fd67625c614
12ea2021d59131
[root@iZbp ~]# ps #此时多出来的2666343是容器的进程
PID TTY TIME CMD
2646243 pts/0 00:00:00 bash
2666343 pts/0 00:00:00 bash
2666546 pts/0 00:00:00 ps
[root@iZbp ~]# docker inspect --format
'{{.State.Pid}}' test #使⽤--format参数直接提取容器
的pid, docker inspect是⽤来获取有关容器的详细信息,其中
{{.State.Pid}}表示获取容器的进程pid。
2666343
#查看test容器中的namespace信息,以及上⾯apache的进程的
namespace信息
[root@iZbp ~]# ll /proc/2666343/ns
total 0
lrwxrwxrwx 1 root root 0 Dec 5 21:03 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 5 21:03 ipc -> 'ipc:
[4026532208]'
lrwxrwxrwx 1 root root 0 Dec 5 20:58 mnt -> 'mnt:
[4026532206]'lrwxrwxrwx 1 root root 0 Dec 5 20:58 net -> 'net:
[4026532211]'
lrwxrwxrwx 1 root root 0 Dec 5 20:58 pid -> 'pid:
[4026532209]'
lrwxrwxrwx 1 root root 0 Dec 5 21:03
pid_for_children -> 'pid:[4026532209]'
lrwxrwxrwx 1 root root 0 Dec 5 21:03 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 21:03
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:58 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 5 21:03 uts -> 'uts:
[4026532207]'
[root@iZbp ~]# ll /proc/2578447/ns/
total 0
lrwxrwxrwx 1 root root 0 Dec 5 20:35 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 ipc -> 'ipc:
[4026531839]'
lrwxrwxrwx 1 root root 0 Dec 5 20:31 mnt -> 'mnt:
[4026532268]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 net -> 'net:
[4026531992]'
lrwxrwxrwx 1 root root 0 Dec 5 20:31 pid -> 'pid:
[4026531836]'4、对⽐得出结论
这⾥的数字就是“命名空间的名字”,数字相同,则表示在同⼀个空间
内,不相同则表示不在同⼀个空间内。若在同⼀个空间内,表示会
发⽣“耦合”或“冲突”,⽐如实验中 43866 和 2 的进程中 net 相同,
则他们不能使⽤相同的端⼝、IP等⽹络栈。但实验中 43866 和 2 的
进程中 mnt 的编号不相同,则不会发⽣冲突。
5、proc ⽬录
proc 是 Linux 系统下⼀个很重要的⽬录。 它跟 /etc,/home 等这些
系统⽬录不同,它不是⼀个真正的⽂件系统, ⽽是⼀个虚拟的⽂件
系统。 它不存在于磁盘, ⽽是存在于系统内存中。
lrwxrwxrwx 1 root root 0 Dec 5 20:35
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:31 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 uts -> 'uts:
[4026531838]'
#cgroup先不要考虑,观察其他的数值是否在同⼀个空间
#只有namespace的user和time没有被隔离。docker默认没有对
user和time的单独namespace/proc/cpuinifo
CPU的信息 (型号、家族、缓存⼤⼩等),对应命
令 top
/proc/meminfo
物理内存、交换空间,对应命令 free
/proc/mounts
已加载的⽂件系统的列表
/proc/devices
可⽤设备的列表
/proc/filesystems
被⽀持的⽂件系统
/proc/modules
已加载的模块
/proc/version
内核版本
/proc/cmdline
系统启动时输⼊的内核命令⾏参数
/proc/XXX
XXX是指以进程PID(数字编号)命名的⽬
录,每⼀个⽬录表示⼀个进程(即线程组)
/proc/swaps
要获知swap空间的使⽤情况
/proc/uptime
获取系统的正常运⾏时间
/proc/fs/nfsd/exports 列出由NFS共享的⽂件系统/proc/kmsg
该⽂件被作为内核⽇志信息源,它可以被
作为⼀个系统信息调⽤的接⼝使⽤
/proc/self
到当前进程/proc⽬录的符号链接,通过这
个⽬录可以获取当前运⾏进程的信息
/proc/pci
挂接在PCI总线上的设备
/proc/tty/driver/serial
串⼝配置、统计信息
/proc/version
系统版本信息,对应系统命令 uname -a
或 lsb_release
/proc/sys/kernel/ostype
/proc/sys/kernel/osrelease
/proc/sys/kernel/version
/proc/sys/kernel/hostname
主机名
/proc/sys/kernel/domainname
域名
/proc/partitions
硬盘设备分区信息
/proc/sys/dev/cdrom/info
CDROM信息/proc/locks
当前系统中所有的⽂件锁
/proc/loadavg
系统负荷信息,对应系统命令 top
/proc/uptime
系统启动后的运⾏时间,对应命
令 uptime
/proc/N[N 对应 pid 号 ]
获取进程运⾏状态,系统命令
ps aux 或 top
1. /proc/N pid为N的进程信息
2. /proc/N/cmdline 进程启动命令
3. /proc/N/cwd 链接到进程当前⼯作⽬录
4. /proc/N/environ 进程环境变量列表
5. /proc/N/exe 链接到进程的执⾏命令⽂件
6. /proc/N/fd 包含进程相关的所有的⽂件描述符
7. /proc/N/maps 与进程相关的内存映射信息
8. /proc/N/mem 指代进程持有的内存,不可读
9. /proc/N/root 链接到进程的根⽬录
10. /proc/N/stat 进程的状态
11. /proc/N/statm 进程使⽤的内存的状态
12. /proc/N/status 进程状态信息,⽐stat/statm更具可读性
13. /proc/self 链接到当前正在运⾏的进程14. /proc/N/ns 程序的namespace空间
六、namespace 隔离项
1、准备⼯作
[root@iZbp ~]# yum -y install gcc gcc-c++ #安装c
语⾔环境
[root@iZbp ~]# vim test.c #编写脚本⽂件
#define _GNU_SOURCE
#include
#include
#include
#include
#include
#include
#define STACK_SIZE (1024 * 1024)
static char child_stack[STACK_SIZE];
char* const child_args[] = {
"/bin/bash",
NULL
};
int child_main(void* args) {
printf("在⼦进程中!\n");
execv(child_args[0], child_args);
return 1;}
int main() {
printf("程序开始: \n");
int child_pid = clone(child_main, child_stack +
STACK_SIZE, SIGCHLD, NULL);
waitpid(child_pid, NULL, 0);
printf("已退出\n");
return 0;
}
[root@iZbp ~]# gcc -Wall test.c -o test.o #编译名
为test.c的c源⽂件
[root@iZbp ~]# ls #查看⽣产源⽂件
test.c test.o
[root@iZbp ~]# ./test.o #执⾏c源⽂件
程序开始:
在⼦进程中!
[root@iZbp ~]# ps af #已完整的格式显示进程信息,显示
所有⽤户的进程,包括其他⽤户的进程
PID TTY STAT TIME COMMAND
2666343 pts/0 Ss+ 0:00 /bin/bash
2646243 pts/0 Ss 0:00 -bash
2726964 pts/0 S 0:00 \_ ./test.o #在
test.o程序下开启了bash
2726965 pts/0 S 0:00 \_ /bin/bash
2727511 pts/0 R+ 0:00 \_ ps af
1360 tty1 Ss+ 0:00 /sbin/agetty -o -p --
\u --noclear tty1 linux1359 ttyS0 Ss+ 0:00 /sbin/agetty -o -p --
\u --keep-baud 115200,38400,9600 ttyS0 vt220
#得到test.o程序的进程为2726965,查看还进程和2号进程之间的
namespace
[root@iZbp ~]# ll /proc/2726965/ns/
total 0
lrwxrwxrwx 1 root root 0 Dec 5 21:24 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 5 21:24 ipc -> 'ipc:
[4026531839]'
lrwxrwxrwx 1 root root 0 Dec 5 21:17 mnt -> 'mnt:
[4026531840]'
lrwxrwxrwx 1 root root 0 Dec 5 21:24 net -> 'net:
[4026531992]'
lrwxrwxrwx 1 root root 0 Dec 5 21:17 pid -> 'pid:
[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 21:24
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 21:24 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 21:24
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 21:17 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 5 21:24 uts -> 'uts:
[4026531838]'
[root@iZbp ~]# ll /proc/2/ns/2、UTS 的隔离
1. UTSnamespace提供了主机名和域名的隔离,这样每个容器就
可以拥有了独⽴的主机名和域名
total 0
lrwxrwxrwx 1 root root 0 Dec 5 20:35 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 ipc -> 'ipc:
[4026531839]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 mnt -> 'mnt:
[4026531840]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 net -> 'net:
[4026531992]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 pid -> 'pid:
[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 uts -> 'uts:
[4026531838]'
#根据结果显示所有数据值⼀致,全部没有被隔离2. 在⽹络上可以被视作⼀个独⽴的节点⽽⾮宿主机上的⼀个进程
[root@iZbp ~]# vim test.c #添加uts隔离设置
static char child_stack[STACK_SIZE];
char* const child_args[] = {
"/bin/bash",
NULL
};
int child_main(void* args) {
printf("在⼦进程中!\n");
sethostname("C测试",8); #添加,设置主机名和需要多少
字符
execv(child_args[0], child_args);
return 1;
}
int main() {
printf("程序开始: \n");
int child_pid = clone(child_main, child_stack +
STACK_SIZE,CLONE_NEWUTS | SIGCHLD, NULL);
#添加 CLONE_NEWUTS |
waitpid(child_pid, NULL, 0);
printf("已退出\n");
return 0;
}
[root@iZbp ~]# gcc -Wall test.c -o uts.o #将修改
的脚本⽣成程序[root@iZbp ~]# ls
test.c test.o uts.o
[root@iZbp ~]# ./uts.o #进⼊程序
程序开始:
在⼦进程中!
[root@C测试 ~]# ps af #程序的⽤户名发⽣改变
PID TTY STAT TIME COMMAND
2666343 pts/0 Ss+ 0:00 /bin/bash
2646243 pts/0 Ss 0:00 -bash
2815042 pts/0 S 0:00 \_ ./uts.o
2815043 pts/0 S 0:00 \_ /bin/bash
#⽣产⼀个新的bash
2815288 pts/0 R+ 0:00 \_ ps af
1360 tty1 Ss+ 0:00 /sbin/agetty -o -p --
\u --noclear tty1 linux
1359 ttyS0 Ss+ 0:00 /sbin/agetty -o -p --
\u --keep-baud 115200,38400,9600 ttyS0 vt220
[root@C测试 ~]#
[root@C测试 ~]# ll /proc/2815043/ns/ #查看该程序的
bash下的namespace
total 0
lrwxrwxrwx 1 root root 0 Dec 5 21:46 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 5 21:46 ipc -> 'ipc:
[4026531839]'
lrwxrwxrwx 1 root root 0 Dec 5 21:44 mnt -> 'mnt:
[4026531840]'lrwxrwxrwx 1 root root 0 Dec 5 21:46 net -> 'net:
[4026531992]'
lrwxrwxrwx 1 root root 0 Dec 5 21:44 pid -> 'pid:
[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 21:46
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 21:46 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 21:46
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 21:44 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 5 21:46 uts -> 'uts:
[4026532269]'
[root@C测试 ~]# ll /proc/2/ns/ #查看2号进程的
namespace
total 0
lrwxrwxrwx 1 root root 0 Dec 5 20:35 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 ipc -> 'ipc:
[4026531839]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 mnt -> 'mnt:
[4026531840]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 net -> 'net:
[4026531992]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 pid -> 'pid:
[4026531836]'3、IPC 隔离
1. 在容器中进程间通信采⽤的⽅法包括常⻅的信号量、消息队列和
共享内存
2. 编辑测试
lrwxrwxrwx 1 root root 0 Dec 5 20:35
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 uts -> 'uts:
[4026531838]'
#对⽐之后UTS隔离了,其他选项没有隔离
#在docker中,每个镜像基本都以⾃⼰所提供的服务命名了⾃⼰的
hostname⽽没有对宿主机产⽣任何影响
[root@C测试 ~]# exit
exit
已退出
[root@iZbp ~]# vim test.c
int main() {
printf("程序开始: \n"); int child_pid = clone(child_main, child_stack +
STACK_SIZE,CLONE_NEWUTS | CLONE_NEWIPC | SIGCHLD,
NULL); #添加CLONE_NEWIPC
[root@iZbp ~]# gcc -Wall test.c -o ipc.o #将修改
后的脚本⽣成程序
[root@iZbp ~]# ls #查看⽣成后的程序
ipc.o test.c test.o uts.o
[root@iZbp ~]# ipcs #⽤来查看进程通信设施的状态
------ Message Queues -------- #显示消息列表
key msqid owner perms used
bytes messages
------ Shared Memory Segments -------- #共享内存
key shmid owner perms bytes
nattch status
------ Semaphore Arrays -------- #信号量
key semid owner perms nsems
0x00000000 10 apache 600 1
0x00000000 11 apache 600 1
0x00000000 12 apache 600 10x00000000 13 apache 600 1
0x00000000 14 apache 600 1
0x00000000 15 apache 600 1
[root@iZbp ~]# ipcmk -Q #创建消息队列
Message queue id: 0
[root@iZbp ~]# ipcmk -Q
Message queue id: 1
[root@iZbp ~]# ipcmk -Q
Message queue id: 2
[root@iZbp ~]# ipcs #查看添加消息队列后的进程通信设施
的状态
------ Message Queues --------
key msqid owner perms used
bytes messages
0x1cc53b4b 0 root 644 0
0
0xfeae48cf 1 root 644 0
0
0xc29931e5 2 root 644 0
0
------ Shared Memory Segments --------
key shmid owner perms bytes
nattch status ------ Semaphore Arrays --------
key semid owner perms nsems
0x00000000 10 apache 600 1
0x00000000 11 apache 600 1
0x00000000 12 apache 600 1
0x00000000 13 apache 600 1
0x00000000 14 apache 600 1
0x00000000 15 apache 600 1
[root@iZbp ~]# ./ipc.o #运⾏ipc.o程序
程序开始:
在⼦进程中!
[root@C测试 ~]# ipcs #在该程序内查看进程通信设施的状态
------ Message Queues -------- #ipc.o的程序内没有消
息队列
key msqid owner perms used
bytes messages
------ Shared Memory Segments --------key shmid owner perms bytes
nattch status
------ Semaphore Arrays --------
key semid owner perms nsems
[root@C测试 ~]# ps af #以完整的格式显示所有⽤户的进
程信息
PID TTY STAT TIME COMMAND
2666343 pts/0 Ss+ 0:00 /bin/bash
732492 pts/0 Ss 0:00 -bash
767041 pts/0 S 0:00 \_ ./ipc.o
767042 pts/0 S 0:00 \_ /bin/bash
#ipc.o程序执⾏bash
768002 pts/0 R+ 0:00 \_ ps af
1360 tty1 Ss+ 0:00 /sbin/agetty -o -p --
\u --noclear tty1 linux
1359 ttyS0 Ss+ 0:00 /sbin/agetty -o -p --
\u --keep-baud 115200,38400,9600 ttyS0 v
[root@C测试 ~]# ll /proc/767042/ns/ # 查看ipc.o程
序下bash的namespace
total 0
lrwxrwxrwx 1 root root 0 Dec 6 08:46 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 6 08:46 ipc -> 'ipc:
[4026532270]'lrwxrwxrwx 1 root root 0 Dec 6 08:45 mnt -> 'mnt:
[4026531840]'
lrwxrwxrwx 1 root root 0 Dec 6 08:46 net -> 'net:
[4026531992]'
lrwxrwxrwx 1 root root 0 Dec 6 08:45 pid -> 'pid:
[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 6 08:46
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 6 08:46 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 6 08:46
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 6 08:45 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 6 08:46 uts -> 'uts:
[4026532269]'
[root@C测试 ~]# ll /proc/2/ns/ #查看2号进程的
namespace,对⽐
total 0
lrwxrwxrwx 1 root root 0 Dec 5 20:35 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 ipc -> 'ipc:
[4026531839]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 mnt -> 'mnt:
[4026531840]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 net -> 'net:
[4026531992]'4、PID 隔离
1. docker容器内不能运⾏包管理器的程序
lrwxrwxrwx 1 root root 0 Dec 5 20:35 pid -> 'pid:
[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 5 20:35 uts -> 'uts:
[4026531838]'
#对⽐后发现ipc的namespace已经不同了,此时的ipc和uts已经实
现隔离
#docker本身是通过socket或tcp进程通信
[root@iZbp ~]# ipcrm -q 0 #删除消息队列
[root@iZbp ~]# ipcrm -q 1
[root@iZbp ~]# ipcrm -q 2[root@iZbp ~]# docker ps -a #查看所有docker容器
CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS NAMES
1af03b3055f7 centos:7 "/bin/bash" 12 hours
ago Up 12 hours test
[root@iZbp ~]# docker exec -it test bash #进⼊到
名为test容器内
[root@1af03b3055f7 /]# yum -y install httpd #在容
器内安装httpd
[root@1af03b3055f7 /]# systemctl start httpd #
在容器内使⽤systemctl启动httpd
Failed to get D-Bus connection: Operation not
permitted #启动失败
1. 失败原因
2. 1. 由于PID的隔离,在不同的命名空间可以有相同的PID
2. PID的命令空间允许每个容器都有⾃⼰的init(PID 1),这
是所有进程的祖先。⽤于管理各种程序初始化任务,并在他
们终⽌时获得孤⽴的⼦进程
3. 进程有两个PID:命名空间内的PID和主机系统上的命名空
间外部的PID
3. 测试未隔离时的效果
[root@iZbp ~]# ps af #查看主机系统上的进程信息
PID TTY STAT TIME COMMAND732492 pts/0 Ss 0:00 -bash
828143 pts/0 R+ 0:00 \_ ps af
1360 tty1 Ss+ 0:00 /sbin/agetty -o -p --
\u --noclear tty1 linux
1359 ttyS0 Ss+ 0:00 /sbin/agetty -o -p --
\u --keep-baud 115200,38400,9600 ttyS0 v
[root@iZbp ~]# ./ipc.o #执⾏ipc.o程序查看PID未隔
离时的效果
程序开始:
在⼦进程中!
[root@C测试 ~]# echo $$ #查看ipc.o程序bash的进程号
828649
[root@C测试 ~]# exit #离开ipc.o程序
exit
已退出
#可以看到未隔离时的PID号时延续主机上⾯的PID,在⼀个独⽴空间
内,第⼀个进程号不是1号进程,⽽是延续主机的进程
1. 测试PID隔离后的效果
[root@iZbp ~]# vim test.c
int main() {
printf("程序开始: \n");
int child_pid = clone(child_main, child_stack +
STACK_SIZE,CLONE_NEWUTS | CLONE_NEWIPC
|CLONE_NEWPID| SIGCHLD, NULL); #添加CLONE_NEWPID
waitpid(child_pid, NULL, 0); printf("已退出\n");
return 0;
}
[root@iZbp ~]# gcc -Wall test.c -o pid.o #将脚本
⽣成程序
[root@iZbp ~]# ls #查看⽣成的pid.o程序
ipc.o pid.o test.c test.o uts.o
[root@iZbp ~]# ./pid.o #执⾏pid.o程序
程序开始:
在⼦进程中!
[root@C测试 ~]# echo $$ #在该程序内查看执⾏bash的进
程号
1 #此时的进程号是1,说明已经是这个空间内的第⼀个进程了
[root@C测试 ~]# ps af #查看完整的所有⽤户的进程信息
PID TTY STAT TIME COMMAND
732492 pts/0 Ss 0:00 -bash
847191 pts/0 S 0:00 \_ ./pid.o
847192 pts/0 S 0:00 \_ /bin/bash
#主机上的进程。有两个进程
848008 pts/0 R+ 0:00 \_ ps af
1360 tty1 Ss+ 0:00 /sbin/agetty -o -p --
\u --noclear tty1 linux
1359 ttyS0 Ss+ 0:00 /sbin/agetty -o -p --
\u --keep-baud 115200,38400,9600 ttyS0 v
[root@C测试 ~]# ll /proc/847192/ns/ #查看主机上
pid.o下bash的进程namespace
total 0lrwxrwxrwx 1 root root 0 Dec 6 09:11 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 ipc -> 'ipc:
[4026532205]'
lrwxrwxrwx 1 root root 0 Dec 6 09:10 mnt -> 'mnt:
[4026531840]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 net -> 'net:
[4026531992]'
lrwxrwxrwx 1 root root 0 Dec 6 09:10 pid -> 'pid:
[4026532206]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11
pid_for_children -> 'pid:[4026532206]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 6 09:10 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 uts -> 'uts:
[4026532204]'
[root@C测试 ~]# ll /proc/2/ns/ #查看2号进程的
namespace
total 0
lrwxrwxrwx 1 root root 0 Dec 6 09:11 cgroup ->
'cgroup:[4026531835]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 ipc -> 'ipc:
[4026531839]'lrwxrwxrwx 1 root root 0 Dec 6 09:11 mnt -> 'mnt:
[4026531840]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 net -> 'net:
[4026531992]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 pid -> 'pid:
[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11
pid_for_children -> 'pid:[4026531836]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 time ->
'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11
time_for_children -> 'time:[4026531834]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 user ->
'user:[4026531837]'
lrwxrwxrwx 1 root root 0 Dec 6 09:11 uts -> 'uts:
[4026531838]'
#对⽐之后,可以看到此时的pid数据值已经不⼀样了
[root@C测试 ~]# pstree
systemd"#"AliYunDun"""10*[{AliYunDun}]
$"AliYunDunMonito"""25*[{AliYunDunMonito}]
$"smartd
$"sshd"""sshd"""sshd"""bash"""pid.o"""bash"""pstre
e #可以看到进程之间的关系
[root@C测试 ~]# ps aux #主机上的1号进程是systemd
USER PID %CPU %MEM VSZ RSS TTY
STAT START TIME COMMANDroot 1 0.0 0.6 184304 12060 ?
Ss Nov30 0:09 /usr/lib/systemd/systemd
root 2 0.0 0.0 0 0 ? S
Nov30 0:00 [kthreadd]
#此时可以看出⽬前查到的都是主机系统上的进程信息,⽽不是新空
间内的。是因为此时的proc⽬录没有改变
[root@C测试 ~]# ls /proc/ #proc⽬录下的进程还是主机
上的进程
1 157 28 434 721 845170
interrupts partitions
10 158 29 435 732015 845172
iomem sched_debug
1004 16 290 437 732482 847191
ioports schedstat
11 160 291 437402 732485 847192
irq scsi
1131 161 292 438 732491 850882
kallsyms self
12 162 295 444 732492 9
kcore slabinfo
1211 17 3 464 743 acpi
keys softirqs
1224 1719 30 466 747 buddyinfo
key-users stat
13 18 300 467 750 bus
kmsg swaps1305 1878 302 468 751 cgroups
kpagecgroup sys
1327 2 31 469 752 cmdline
kpagecount sysrq-trigger
1341 20 32 470 753 consoles
kpageflags sysvipc
1344 22 33 471 759 cpuinfo
loadavg thread-self
1347 23 34 472 779100 crypto
locks timer_list
1349 24 35 473 791 devices
mdstat tty
1359 2578447 36 579 794 diskstats
meminfo uptime
1360 2578448 37 6 796 dma
misc version
14 2578449 38 614 799312 driver
modules vmallocinfo
1435 2578450 4 62 825610 execdomains
mounts vmstat
15 2578451 40 681 825617 fb
mtrr zoneinfo
155 26 41 693437 827638 filesystems
net
156 27 428472 719 844328 fs
pagetypeinfo5、MOUNT 隔离
1. MOUNT命名空间是linux系统上实现的第⼀种类型的命名空间。
所以它的标识⽐较特殊是CLONE_NEWNS
2. 隔离后,不同mountnamespace中的⽂件结构发⽣变化也互不
影响
3. mount传播挂载命令。默认所有挂载都是私有的
4. 1. 设置共享挂载:mount --make-shared 。共享挂载克隆的
挂载对象也是共享挂载;他们相互传播挂载事件
2. 从属挂载:mount --make-slave 。从属挂载克隆的挂载对
象也是从属的挂载
3. 将⼀个从属挂载对象设置为共享、从属挂载,可以执⾏
mount --make-shared
1. 1. 如果想把修改过的挂载对象重新标记为私有
mount --make-private
1. 1. 挂载对象标记为不可绑定
mount --make-unbindable
#proc⽬录没有改变是因为没有对⽂件系统进程隔离,需要对mount
隔离1. 测试mount挂载
[root@C测试 ~]# vim test.c #添加mount隔离
int main() {
printf("程序开始: \n");
int child_pid = clone(child_main, child_stack +
STACK_SIZE,CLONE_NEWUTS | CLONE_NEWIPC
|CLONE_NEWPID| CLONE_NEWNS| SIGCHLD, NULL); #添加
CLONE_NEWNS
waitpid(child_pid, NULL, 0);
printf("已退出\n");
return 0;
}
[root@C测试 ~]# gcc -Wall test.c -o mnt.o #将脚本
⽣成程序
[root@C测试 ~]# ls #查看⽣成后的程序⽂件
ipc.o mnt.o pid.o test.c test.o uts.o
[root@C测试 ~]# ./mnt.o #运⾏mnt程序
程序开始:
在⼦进程中!
#此时并没有实现完全隔离,需要⼿动执⾏mount命令
[root@C测试 ~]# mount --make-private -t proc proc
/proc/ #对容器内的proc⽬录设置为私有挂载
[root@C测试 ~]# ls /proc/ #此时查看proc⽬录,发现已
经只有容器内的进程信息了1 crypto interrupts kpagecgroup
mounts slabinfo tty
46 devices iomem kpagecount
mtrr softirqs uptime
acpi diskstats ioports kpageflags
net stat version
buddyinfo dma irq loadavg
pagetypeinfo swaps vmallocinfo
bus driver kallsyms locks
partitions sys vmstat
cgroups execdomains kcore mdstat
sched_debug sysrq-trigger zoneinfo
cmdline fb keys meminfo
schedstat sysvipc
consoles filesystems key-users misc
scsi thread-self
cpuinfo fs kmsg modules
self timer_list
[root@C测试 ~]# ps aux #查看容器所有进程信息,只有容
器内的进程
USER PID %CPU %MEM VSZ RSS TTY
STAT START TIME COMMAND
root 1 0.0 0.3 27824 5856 pts/0 S
10:19 0:00 /bin/bash
root 47 0.0 0.2 58732 3924 pts/0
R+ 10:22 0:00 ps aux
[root@C测试 ~]# exitexit
已退出
#这个挂载修改后还会影响宿主机上⾯的挂载,宿主机也需要重新挂
载才可以还原
[root@iZbp ~]# mount --make-private -t proc proc
/proc/ #在宿主机上⾯执⾏proc的挂载
[root@iZbp ~]# ls /proc/ #查看proc⽬录
1 13 18 300 467 794
iomem sched_debug
10 1305 1878 302 468 796
ioports schedstat
1002231 1327 2 31 469 9
irq scsi
1004 1341 20 32 470 941511
kallsyms self
1033693 1344 22 33 471 991980
kcore slabinfo
1052123 1347 23 34 472 acpi
keys softirqs
1054700 1349 24 35 473 buddyinfo
key-users stat
1065188 1359 2578447 36 579 bus
kmsg swaps
1065189 1360 2578448 37 6 cgroups
kpagecgroup sys
1071096 14 2578449 38 614 cmdline
kpagecount sysrq-trigger1076512 1435 2578450 4 62 consoles
kpageflags sysvipc
1077826 15 2578451 40 681 cpuinfo
loadavg thread-self
1077830 155 26 41 719 crypto
locks timer_list
1077895 156 27 428472 721 devices
mdstat tty
1078161 157 28 434 743 diskstats
meminfo uptime
1078162 158 29 435 747 dma
misc version
1080287 16 290 437 750 driver
modules vmallocinfo
11 160 291 437402 751 execdomains
mounts vmstat
1131 161 292 438 752 fb
mtrr zoneinfo
12 162 295 444 753 filesystems
net
1211 17 3 464 759 fs
pagetypeinfo
1224 1719 30 466 791 interrupts
partitions
#此时宿主机上⾯的proc⽬录恢复正常[root@iZbp ~]# cat /boot/config-4.18.0-
305.3.1.el8.x86_64 | grep -i ns #查看那些是需要内核实
现的
CONFIG_INSTRUCTION_DECODER=y
CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
CONFIG_UTS_NS=y
CONFIG_TIME_NS=y
CONFIG_IPC_NS=y
CONFIG_USER_NS=y
CONFIG_PID_NS=y
CONFIG_NET_NS=y。。。。。
#这些namespace是没有被mount的
1. systemd是使⽤内核,所以依旧⽆法⽤systemd进程启动程序。
2. 解决⽅案⼀:/sbin/init是systemd的软连接。可以使⽤/sbin/init
进⼊容器。此⽅法在最新版本中已经不建议使⽤
[root@iZbp ~]# docker run -d --name test --
privileged rockylinux /sbin/init #增加--
privileged参数才能有权限执⾏systemd
795851a713f9ded5b250dfd0861c4dc97490409a5a745c4b28
587267e573ca1c
[root@iZbp ~]# docker exec -it test bash #进⼊容器
[root@795851a713f9 /]# yum -y install httpd #安装
httpd[root@795851a713f9 /]# systemctl start httpd #使
⽤systemd启动httpd程序
[root@iZbp ~]# which ps #在宿主机上⾯查看ps命令的安装
包
/usr/bin/ps
[root@iZbp ~]# rpm -qf /usr/bin/ps
procps-ng-3.3.15-6.el8.x86_64
[root@795851a713f9 /]# yum -y install procps-ng
#安装ps命令
USER PID %CPU %MEM VSZ RSS TTY
STAT START TIME COMMAND
root 1 0.1 0.5 89900 10200 ?
Ss 02:39 0:00 /sbin/init
root 18 0.0 0.4 87356 8120 ?
Ss 02:39 0:00 /usr/lib/systemd/systemd
dbus 26 0.0 0.2 54056 4172 ?
Ss 02:39 0:00 /usr/bin/dbus-daemon --s
root 45 0.0 0.2 19352 3712 pts/0
Ss 02:39 0:00 bash
root 135 0.0 0.6 258080 10852 ?
Ss 02:39 0:00 /usr/sbin/httpd -DFOREGR
apache 136 0.0 0.4 260664 7956 ? S
02:39 0:00 /usr/sbin/httpd -DFOREGR
apache 137 0.0 0.5 1908356 9588 ?
Sl 02:39 0:00 /usr/sbin/httpd -DFOREGR
apache 138 0.0 0.5 1777220 9700 ?
Sl 02:39 0:00 /usr/sbin/httpd -DFOREGRapache 139 0.0 0.5 1777220 9700 ?
Sl 02:39 0:00 /usr/sbin/httpd -DFOREGR
root 358 0.0 0.2 51864 3808 pts/0
R+ 02:40 0:00 ps aux
1. 解决⽅案⼆:直接使⽤execstart启动
[root@iZbp ~]# docker run -itd --name ssh
rockylinux bash #创建⼀个容器,⽤来演示sshd服务在容器
内如何启动
0cac21a08a57ee6de38e16e744d07d8d5a72d6eda40a9259fc
1b3997c5ecff7f
[root@iZbp ~]# docker exec -it ssh bash #进⼊
[root@0cac21a08a57 /]# yum -y install httpd #安装
httpd服务
[root@0cac21a08a57 /]# cat
/usr/lib/systemd/system/httpd.service #找到启动⽂
件
ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND #
找到启动程序命令的路径
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
[root@0cac21a08a57 /]# /usr/sbin/httpd $OPTIONS -
DFOREGROUND & #使⽤命令启动程序,并放在后台运⾏
[1] 549[root@0cac21a08a57 /]# AH00558: httpd: Could not
reliably determine the server's fully qualified
domain name, using 172.17.0.2. Set the
'ServerName' directive globally to suppress this
message
[root@0cac21a08a57 /]# ps aux #查看进程已经开始运⾏
USER PID %CPU %MEM VSZ RSS TTY
STAT START TIME COMMAND
root 1 0.0 0.2 19240 3740 pts/0
Ss+ 02:47 0:00 bash
root 13 0.0 0.2 19352 3736 pts/1
Ss 02:48 0:00 bash
root 549 0.3 0.6 258080 10744 pts/1 S
02:55 0:00 /usr/sbin/httpd -DFOREGR
apache 550 0.0 0.4 260664 8044 pts/1 S
02:55 0:00 /usr/sbin/httpd -DFOREGR
apache 551 0.0 0.6 1908344 11696 pts/1
Sl 02:55 0:00 /usr/sbin/httpd -DFOREGR
apache 552 0.0 0.5 1777208 9648 pts/1
Sl 02:55 0:00 /usr/sbin/httpd -DFOREGR
apache 553 0.0 0.5 1777208 9648 pts/1
Sl 02:55 0:00 /usr/sbin/httpd -DFOREGR
root 765 0.0 0.2 51864 3780 pts/1
R+ 02:55 0:00 ps aux
#在宿主机上查看docker的IP地址
[root@iZbp /]# docker inspect ssh |grep 172 #过
滤dockerip的详细信息"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
#docker的IP地址
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
[root@iZbp /]# curl 172.17.0.2
#访问成功后显示httpd的图形测试⻚⾯
#启动容器内sshd服务
[root@iZbp ~]# docker exec -it ssh bash
[root@0cac21a08a57 /]# yum -y install passwd
iproute openssh-server #安装sshd需要的⼀些必要命令
#passwd:ssh连接需要密码,所以需要passwd设置root的密码
#openssh-server:ssh服务
[root@0cac21a08a57 /]# passwd root #设置root密码
Changing password for user root.
New password:
BAD PASSWORD: The password is shorter than 8
characters
Retype new password:
passwd: all authentication tokens updated
successfully.
[root@0cac21a08a57 /]# /usr/sbin/sshd -D $OPTIONS
$CRYPTO_POLICY #启动sshd服务提示缺少三个秘钥⽂件
Unable to load host key: /etc/ssh/ssh_host_rsa_keyUnable to load host key:
/etc/ssh/ssh_host_ecdsa_key
Unable to load host key:
/etc/ssh/ssh_host_ed25519_key
sshd: no hostkeys available -- exiting.
[root@0cac21a08a57 /]# ssh-keygen -f
/etc/ssh/ssh_host_rsa_key #创建秘钥⽂件,回⻋使⽤默认
配置
[root@0cac21a08a57 /]# ssh-keygen -f
/etc/ssh/ssh_host_ecdsa_key
[root@0cac21a08a57 /]# ssh-keygen -f
/etc/ssh/ssh_host_ed25519_key
[root@0cac21a08a57 /]# vi /etc/ssh/sshd_config
PermitRootLogin yes #允许root⽤户登录
#UsePAM yes # #注释PAM认证,
[root@0cac21a08a57 /]# /usr/sbin/sshd -D & #启动
sshd服务
[1] 851
[root@0cac21a08a57 /]# ip a #查看ip地址
1: lo: mtu 65536 qdisc
noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd
00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
29: eth0@if30:
mtu 1500 qdisc noqueue state UP group default6、NETWORK 隔离
1. 提供与⽹络相关的系统资源的隔离
2. 每个⽹络命名空间都有⾃⼰的⽹络设备、IP 地址、ip 路由表、
端⼝、/rpto⽬录等
3. 宿主机和容器的⽹络连接到⼀起并不发⽣冲突就是 net 隔离。
link/ether 02:42:ac:11:00:02 brd
ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope
global eth0
valid_lft forever preferred_lft forever
#在宿主上远程连接容器测试
The authenticity of host '172.17.0.2 (172.17.0.2)'
can't be established.
RSA key fingerprint is
SHA256:FE6korMibbb8b1GzhYyn0YfbuxL2dw1XYjjfINfILAU
.
Are you sure you want to continue connecting
(yes/no/[fingerprint])? yes
Warning: Permanently added '172.17.0.2' (RSA) to
the list of known hosts.
[root@0cac21a08a57 ~]#7、USER 隔离
1. 隔离⽤户和组的ID号
2. 进程的⽤于ID 和组ID在⽤户命名空间内外可能不同
3. 进程对⽤户 命名空间内的操作具有完全的root权限,但对于空
间外的操作,该进程没有特权
七、cgroup:资源控制
1、限制容器对 CPU 的使⽤
1. 所有容器可以平等地使⽤host CPU资源并且没有限制。
2. docker可以通过-c或--cpu-shares设置容器使⽤CPU的权重。默
认1024。
3. 为了实验的效果,将cpu改为1核1G。
#下载⼀个测试镜像progrium/stress(⽤于对系统资源(如 CPU
和内存)进⾏压⼒测试的⼯具)
[root@localhost ~]# docker pull progrium/stress
#下载⼀个测试镜像progrium/stress
Using default tag: latest
latest: Pulling from progrium/stress[DEPRECATION NOTICE] Docker Image Format v1, and
Docker Image manifest version 2, schema 1 support
will be removed in an upcoming release. Suggest
the author of docker.io/progrium/stress:latest to
upgrade the image to the OCI Format, or Docker
Image manifest v2, schema 2. More information at
https://docs.docker.com/go/deprecated-image-specs/
a3ed95caeb02: Pull complete
871c32dbbb53: Pull complete
dbe7819a64dd: Pull complete
d14088925c6e: Pull complete
58026d51efe4: Pull complete
7d04a4fe1405: Pull complete
1775fca35fb6: Pull complete
5c319e267908: Pull complete
Digest:
sha256:e34d56d60f5caae79333cee395aae93b74791d50e38
41986420d23c2ee4697bf
Status: Downloaded newer image for
progrium/stress:latest
docker.io/progrium/stress:latest
[root@localhost ~]# docker images #查看docker的全
部镜像
REPOSITORY TAG IMAGE ID CREATED
SIZE
nginx latest 605c77e624dd 23
months ago 141MBprogrium/stress latest db646a8f4087 9 years
ago 282MB
1. 启动aa容器cpu优先级别设置1024
[root@localhost ~]# docker run -itd --name aa --
cpu-shares 1024 progrium/stress --cpu 1
fb5b092c6bdaa8c41cdf3a5c4ae9da99a465440814e372b1ef
85d9de1db2758a
1. 启动bb容器cpu优先级别设置为512
[root@localhost ~]# docker run -itd --name bb --
cpu-shares 512 progrium/stress --cpu 1
2c5ea28903e5eafb2a6a1389fedc4704d3e75bfb63c2160fd5
11fd43d617c5ed
1. 查看确定后4227就是aa容器、4293就是bb容器(此结果为1核
1G)
#此结果使⽤2核2G的状态[root@haha cpu]# docker run -itd --name bb --cpu
shares 2048 progrium/stress --cpu 2
d97c8fe3b39ca69e0dc4b33081b8a837e365824ccab5574a5d
9ae10f83727bf8
[root@haha cpu]# docker run -itd --name aa --cpu
shares 1024 progrium/stress --cpu 2
ac6a659eadaca579f5349d6913c7384c80e091a49781e6a296
c54440fe1b4870
[root@haha cpu]# top
top - 17:25:37 up 2:50, 1 user, load average:
5.08, 2.55, 1.31
Tasks: 126 total, 5 running, 121 sleeping, 0
stopped, 0 zombie
%Cpu(s): 97.5 us, 1.8 sy, 0.0 ni, 0.0 id, 0.0
wa, 0.5 hi, 0.2 si, 0.0 st
MiB Mem : 1718.4 total, 181.8 free, 357.1
used, 1179.5 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0
used. 1195.5 avail Mem
PID USER PR NI VIRT RES SHR S
%CPU %MEM TIME+ COMMAND
542947 root 20 0 7320 96 0 R
69.0 0.0 0:04.22 stress
542948 root 20 0 7320 96 0 R
64.3 0.0 0:03.11 stress 542362 root 20 0 7320 96 0 R
28.7 0.0 0:11.87 stress
542363 root 20 0 7320 96 0 R
28.7 0.0 0:12.02 stress
1. 由于cgroup是伪⽂件系统的⽅式,可以直接修改⽂件
[root@localhost ~]# docker ps -a
CONTAINER ID IMAGE COMMAND
CREATED STATUS
PORTS NAMES
2c5ea28903e5 progrium/stress "/usr/bin/stress
--v…" 4 minutes ago Up 4 minutes
bb
fb5b092c6bda progrium/stress "/usr/bin/stress
--v…" 4 minutes ago Up 4 minutes
aa
a44e1dce79c3 progrium/stress "/usr/bin/stress
--v…" 12 minutes ago Exited (1) 6 minutes ago
nice_golick
24c4a7961c24 progrium/stress "/usr/bin/stress
--v…" 15 minutes ago Exited (1) 12 minutes ago
sad_goldberg
[root@localhost ~]# cd
/sys/fs/cgroup/cpu/docker/cd10d4993cd21103c7b62638
7a1ede7907c313f164fa8506fe7f1839343a7964[root@localhost
cd10d4993cd21103c7b626387a1ede7907c313f164fa8506fe
7f1839343a7964]# ls
cgroup.clone_children cpuacct.usage
cpuacct.usage_percpu_sys cpuacct.usage_user
cpu.rt_period_us cpu.stat
cgroup.procs cpuacct.usage_all
cpuacct.usage_percpu_user cpu.cfs_period_us
cpu.rt_runtime_us notify_on_release
cpuacct.stat cpuacct.usage_percpu
cpuacct.usage_sys cpu.cfs_quota_us
cpu.shares tasks
[root@localhost
cd10d4993cd21103c7b626387a1ede7907c313f164fa8506fe
7f1839343a7964]# cat cpu.shares
512
[root@localhost
cd10d4993cd21103c7b626387a1ede7907c313f164fa8506fe
7f1839343a7964]# echo 1024 > cpu.shares
[root@localhost
cd10d4993cd21103c7b626387a1ede7907c313f164fa8506fe
7f1839343a7964]# top
1. 再次使⽤top查看,此时两个进程各占50左右(1核1G)2、限制容器对内存的使⽤
1. 内存限额与操作系统类似,容器可以使⽤的内存包括两个部分:
物理内存和swap。
2. docker可以通过下⾯两组参数控制容器内存的使⽤量。
#此时是2核2G的结果
[root@haha cpu]# docker run -itd --name bb --cpu
shares 2048 progrium/stress --cpu 2
493c9fae26670a4e9fec0633b67aeba0a1f337db381880b652
7809a6d31e4c75
[root@haha cpu]# docker run -itd --name aa --cpu
shares 2048 progrium/stress --cpu 2
01b20f41d8790ba194f25bf2949f7a170c56865f53750b5611
03315d9c80aa25
[root@haha cpu]# top
PID USER PR NI VIRT RES SHR S
%CPU %MEM TIME+ COMMAND
575051 root 20 0 7320 96 0 R
49.2 0.0 0:14.60 stress
574756 root 20 0 7320 96 0 R
47.8 0.0 0:15.51 stress
574755 root 20 0 7320 96 0 R
46.8 0.0 0:16.63 stress
575052 root 20 0 7320 96 0 R
45.5 0.0 0:10.77 stress3. 1. -m或-memory:设置内存使⽤的限额
2. --memory-swap:设置内存+swap 的使⽤限额
[root@localhost ~]# docker run -itd -m 200M --
memory-swap=300M nginx
d66d856f0b284acb0501ab7c5c4c6d57b20e33d63d14cdd84e
cce1c7ea7b9ec3
#其含义是允许该容器最多使⽤ 200M 的内存和 100M 的
swap。默认情况下,上⾯两组参数为 -1,即对容器内存和 swap
的使⽤没有限制。使⽤ progrium/stress 镜像来为容器分配内
存。该镜像可⽤于对容器执⾏压⼒测试。
[root@localhost ~]# docker run -it -m 280M --
memory-swap=300M progrium/stress --vm 1 --vm-bytes
250M #为每个线程分配的内存要⼩于内存总量
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1
vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [7] forked
stress: dbug: [7] allocating 262144000 bytes ...
stress: dbug: [7] touching bytes in strides of
4096 bytes ...
stress: dbug: [7] freed 262144000 bytes
stress: dbug: [7] allocating 262144000 bytes ...
stress: dbug: [7] touching bytes in strides of
4096 bytes ...
stress: dbug: [7] freed 262144000 bytesstress: dbug: [7] allocating 262144000 bytes ...
stress: dbug: [7] touching bytes in strides of
4096 bytes ...
stress: dbug: [7] freed 262144000 bytes
stress: dbug: [7] allocating 262144000 bytes ...
# --vm 1 :启动1个内存⼯作线程
# --vm-bytes 280M :每个线程分配280M内存
1. 如果让⼯作线程分配的内存超过 380M,结果如下:[root@localhost ~]# docker run -it -m 200M --
memory-swap=300M progrium/stress --vm 1 --vm-bytes
380M #380M超过规定内存200M⼤⼩
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1
vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [7] forked
stress: dbug: [7] allocating 398458880 bytes ...
stress: dbug: [7] touching bytes in strides of
4096 bytes ...
stress: FAIL: [1] (416) <-- worker 7 got signal 9
stress: WARN: [1] (418) now reaping child worker
processes
stress: FAIL: [1] (422) kill error: No such
process
stress: FAIL: [1] (452) failed run completed in 1s
# 分配的内存超过限额,stress 线程报错,容器退出。
1. 如果在启动容器时只指定-m⽽不指定--memory-swap,那么--
memory-swap默认为-m的两倍,⽐如:
[root@localhost ~]# docker run -it -m 200M nginx
#此时容器最多使⽤200M物理内存和200M的swap
注:容器最多使⽤ 200M 物理内存和 200M swap。3、限制 DPS 和 IOPS 的使⽤
1. bps是byte per second,每秒读写的数据量
2. iops是io per second,每秒IO的次数
3. 参数
--device-read-bps:限制读某个设备的bps
--device-write-bps:限制写某个设备的bps
--device-read-iops:限制读某个设备的iops
--device-write-iops:限制写某个设备的iops
[root@localhost ~]# docker run -it --device-write
bps /dev/mapper/rl-root:30MB rockylinux
[root@24b6f6188dc7 /]# time dd if=/dev/zero
of=test.bak bs=1M count=800 oflag=direct
800+0 records in
800+0 records out
838860800 bytes (839 MB, 800 MiB) copied, 21.9722
s, 38.2 MB/s
real 0m21.975s
user 0m0.001s
sys 0m0.145s
[root@24b6f6188dc7 ~]# exit
exit通过 dd 测试在容器中写磁盘的速度。因为容器的⽂件系统是在
host /dev/sda 上的,在容器中写⽂件相当于对 host /dev/sda 进⾏
写操作。另外,oflag=direct指定⽤ direct IO ⽅式写⽂件,这样--
device-write-bps才能⽣效。结果表明,bps 41.9 MB/s 。作为对⽐
测试,如果不限速,结果如下:
4、限制容器对 CPU、内存、DPS、IOPS 的使⽤
⼋、chroot:切换根⽬录
[root@localhost ~]# docker run rockylinux
[root@localhost ~]# time dd if=/dev/zero
of=test.bak bs=1M count=800 oflag=direct
记录了800+0 的读⼊
记录了800+0 的写出
838860800 bytes (839 MB, 800 MiB) copied, 11.3069
s, 74.2 MB/s
real 0m11.329s
user 0m0.001s
sys 0m0.132s
[root@haha cpu]# docker run -itd --name test --
cpu-shares 1024 -m 200M --memory-swap=300M --
device-write-bps /dev/vda:30MB rockylinux
d844f77071177114cf542bcc7722dbbc739816de91271282fd
69e2e7a2b2b9f3⼋、chroot:切换根⽬录
1、通过 chroot 运⾏ busybox
busybox:⼀个集成了⼀百多个最常⽤Linux命令和⼯具的软件
⼯具箱,它在单⼀的可执⾏⽂件中提供了精简的Unix⼯具集。
BusyBox可运⾏于多款POSIX环境操作系统中,如Linux(包括
Android)、Hurd、FreeBSD等。
$(docker create busybox):将 docker create busybox 这条命
令的执⾏结果作为变量。
docker export :docker export 命令将所指定的 Docker 容器
进⾏导出操作。
|:管道符号⽤于将前⼀个命令的输出连接到下⼀个命令的输
⼊。
tar -C rootfs -xvf -:这部分命令使⽤tar命令来解压缩并提取tar
归档中的⽂件。
[root@doc ~]# cd /
[root@doc /]# mkdir test
[root@doc /]# docker export $(docker create
busybox) | tar -C test -xvf -
[root@doc /]# chroot test /bin/pwd # 通过chroot
执⾏pwd命令,发现根⽬录位置改变到了test
/-Crootfs:将⽂件提取到指定的⽬录rootfs中。这⾥的rootfs
表示⽂件提取的⽬标路径
-xvf -:通过-xvf选项解压缩并提取⽂件,其中“-”表示输⼊
来⾃于前⼀个命令的标准输出。
2、chroot 运⾏ sh
/bin/bash 报错,因为导⼊的 busybox 镜像内不包含
/bin/bash,只能指定 /bin/sh 执⾏ shell
3、检查 /bin/sh 的根⽬录
[root@doc /]# chroot test /bin/bash
chroot: failed to run command ‘/bin/bash’: No such
file or directory
[root@doc /]# chroot test /bin/sh
/ #4、通过 chroot 制作简单系统
(1)创建⼩型系统的根⽬录
(2)复制命令到⼩根⽬录
[root@doc /]# chroot test /bin/sh
/ # echo $$
3552
[root@doc /]# pidof -s sh # 所以当前运⾏的chroot的
sh的进程号为3552
3552
[root@doc /]# ls -ld /proc/3552/root # 查询PID为
3552的进程根⽬录
lrwxrwxrwx. 1 root root 0 12⽉ 12 10:57
/proc/3552/root -> /test # 确认该进程的根⽬录被映射到
了/test上
[root@doc /]# mkdir linux # 这个linux会作为即将创建
的⼩型系统的根⽬录
[root@doc /]# cd linux/
[root@doc linux]# mkdir -p ./usr/bin/
[root@doc linux]# mkdir lib
[root@doc linux]# mkdir lib64
[root@doc linux]# which bash # 查看bash命令的路径
/usr/bin/bash[root@doc linux]# cp -v /usr/bin/bash ./usr/bin/
# 复制bash命令新系统的根⽬录下
'/usr/bin/bash' -> './usr/bin/bash'
[root@doc linux]# ldd /usr/bin/bash # 查看bash
⽂件的动态依赖关系,输出依赖的共享库及版本
linux-vdso.so.1 (0x00007ffdcfe8d000)
libtinfo.so.6 => /lib64/libtinfo.so.6
(0x00007ff3942ab000)
libdl.so.2 => /lib64/libdl.so.2
(0x00007ff3940a7000)
libc.so.6 => /lib64/libc.so.6
(0x00007ff393ce1000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff3947f6000)
[root@doc linux]# cp /lib64/libtinfo.so.6
/lib64/libdl.so.2 /lib64/libc.so.6 /lib64/ld
linux-x86-64.so.2 ./lib64/
# 将依赖共享库添加到⼩根⽬录的lib64⽬录下
[root@doc ~]# chroot /linux /usr/bin/bash # 测试
给个bash运⾏
bash-4.4# echo $$ # 查看当前进程的pid号
3728
复制命令的⽅法都⼀样,先复制命令程序,再查看依赖 lib 库⽂
件,然后根据信息,依次复制 lib 库⽂件到⼩型系统中的 lib 或
lib64 内
[root@doc linux]# cp /usr/bin/ls ./usr/bin/[root@doc linux]# ldd /usr/bin/ls
linux-vdso.so.1 (0x00007ffec15b6000)
libselinux.so.1 => /lib64/libselinux.so.1
(0x00007f619c99e000)
libcap.so.2 => /lib64/libcap.so.2
(0x00007f619c796000)
libc.so.6 => /lib64/libc.so.6
(0x00007f619c3d0000)
libpcre2-8.so.0 => /lib64/libpcre2-8.so.0
(0x00007f619c14c000)
libdl.so.2 => /lib64/libdl.so.2
(0x00007f619bf48000)
/lib64/ld-linux-x86-64.so.2 (0x00007f619cdec000)
libpthread.so.0 => /lib64/libpthread.so.0
(0x00007f619bd28000)
[root@doc linux]# cp /lib64/libselinux.so.1
/lib64/libcap.so.2 /lib64/libc.so.6
/lib64/libpcre2-8.so.0 /lib64/libdl.so.2
/lib64/ld-linux-x86-64.so.2
/lib64/libpthread.so.0 /linux/lib64/
[root@doc linux]# chroot /linux/ /usr/bin/bash
bash-4.4# ls
lib lib64 usr
bash-4.4# echo $$ # 因为之前退出过这个⼩系统的bash,
所以再进时,pid号就会发⽣改变
3810
⼀、Docker 私有仓库
Docker 仓库(Repository)集中存放镜像的地⽅,⽽注册服务器
(Registry)是存放仓库的具体服务器。仓库可以被认为是⼀个具体
的项⽬或⽬录。
Docker 公共仓库:https://hub.docker.com
⼆、Docker 私有仓库的作⽤
1. 镜像上传到公共仓库不⽅便管理,且仅需要局域⽹⽤户之间传递
镜像的情况,需要使⽤私有仓库。
2. 节省⽹络带宽,不需要都去公共仓库下载镜像,只需要从私有仓
库下载即可。
3. 提供镜像资源利⽤,针对公司内部开发,不能联⽹情况下,有⼀
些使⽤到的镜像可以推送到本地的私有仓库中,以供内部开发⼈
员便捷下载使⽤。
三、搭建 Docker 私有仓库的⽅案
1. docker 官⽅提供的搭建私有仓库⼯具 registry。
2. harbor 私有仓库。
四、搭建 docker 私有仓库操作系统
IP 地址
主机名
docker 版本
Rocky8.7
192.168.15.3
doc
docker24.0.7
四、搭建 docker 私有仓库
1、部署环境
2、下载部署 registry
[root@doc ~]# docker pull registry
Using default tag: latest
latest: Pulling from library/registry
79e9f2f55bf5: Pull complete
0d96da54f60b: Pull complete
5b27040df4a2: Pull complete
e2ead8259a04: Pull complete
3790aef225b9: Pull complete
Digest:
sha256:169211e20e2f2d5d115674681eb79d21a217b296b43
374b8e39f97fcf866b375
Status: Downloaded newer image for registry:latest
docker.io/library/registry:latest
[root@doc ~]# docker run -itd --volume
/opt/data/registry/:/var/lib/registry -p 5000:5000
--restart=always --name registry registry:latest
# 启动registry容器。# --volume:挂载,挂载源:挂载点。
# -p:映射端⼝。
# --restart=always:重启策略。
# name registry:容器名。
9ab3d198bf059ab7db6f6934d6725874ba4bdc73d889da8b4b
a692575104e077
[root@doc ~]# docker ps
CONTAINER ID IMAGE COMMAND
CREATED STATUS PORTS
NAMES
9ab3d198bf05 registry:latest "/entrypoint.sh
/etc…" 5 seconds ago Up 4 seconds
0.0.0.0:5000->5000/tcp, :::5000->5000/tcp
registry
[root@doc ~]# netstat -anpt | grep 5000
tcp 0 0 0.0.0.0:5000
0.0.0.0:* LISTEN 7865/docker
proxy
tcp6 0 0 :::5000 :::*
LISTEN 7872/docker-proxy
[root@doc ~]# curl
http://127.0.0.1:5000/v2/_catalog # 查看镜像仓库列
表
{"repositories":[]} # 当前未上传任何镜像所以为空3、上传镜像到私有仓库
4、问题错误
[root@doc ~]# docker images
REPOSITORY TAG IMAGE ID CREATED
SIZE
busybox latest beae173ccac6 23 months
ago 1.24MB
nginx latest 605c77e624dd 23 months
ago 141MB
registry latest b8604a3fe854 2 years ago
26.2MB
[root@doc ~]# docker tag nginx:latest
192.168.15.3:5000/nginx:v1
# 改名,被上传镜像格式:域名或IP地址+端⼝/原镜像名
[root@doc ~]# docker push
192.168.15.3:5000/nginx:v1
The push refers to repository
[192.168.15.3:5000/nginx]
Get "https://192.168.15.3:5000/v2/": http: server
gave HTTP response to HTTPS client
# 报错(1)报错情况
(2)报错原因
因为Docker 从 1.3.X 之后默认 docker registry 使⽤的是 https,所
以当⽤dockerpull/push 命令下载、上传远程镜像时,如果远程
docker registry 是⾮ https 的时候就会报上⾯的错误,所以需要修改
⼀下docker启动参数。
(3)错误处理
[root@doc ~]# docker push
192.168.15.3:5000/nginx:v1
The push refers to repository
[192.168.15.3:5000/nginx]
Get "https://192.168.15.3:5000/v2/": http: server
gave HTTP response to HTTPS client
# 报错
[root@doc ~]# vim
/usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --
containerd=/run/containerd/containerd.sock --
insecure-registry 192.168.15.3:5000 # 添加参数
[root@doc ~]# systemctl daemon-reload
[root@doc ~]# systemctl restart docker.service--insecure-registry:⼀个⽤于将 Docker 客户端配置为信任不安
全的 Docker Registry 的选项。在默认情况下,Docker 客户端
只信任通过 HTTPS 进⾏通信的 Docker Registry,以确保安全
性。
5、再次上传镜像
[root@doc ~]# docker push
192.168.15.3:5000/nginx:v1
The push refers to repository
[192.168.15.3:5000/nginx]
d874fd2bc83b: Pushed
32ce5f6a5106: Pushed
f1db227348d0: Pushed
b8d6e692a25e: Pushed
e379e8aedd4d: Pushed
2edcec3590a4: Pushed
v1: digest:
sha256:ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0b
fd5c4c20a2fa2aaa7ede3 size: 1570
[root@doc ~]# curl
http://127.0.0.1:5000/v2/_catalog
{"repositories":["nginx"]} # 上传成功
[root@doc ~]# curl
http://127.0.0.1:5000/v2/nginx/tags/list
{"name":"nginx","tags":["v1"]} # 查看nginx镜像版
本6、拉取私有镜像
[root@doc ~]# ls
/opt/data/registry/docker/registry/v2/repositories
/ # 镜像存放于宿主机的位置
nginx
[root@doc ~]# docker rmi
192.168.15.3:5000/nginx:v1 # 先删除刚才的镜像
Untagged: 192.168.15.3:5000/nginx:v1
Untagged:
192.168.15.3:5000/nginx@sha256:ee89b00528ff4f02f24
05e4ee221743ebc3f8e8dd0bfd5c4c20a2fa2aaa7ede3
[root@doc ~]# docker pull
192.168.15.3:5000/nginx:v1 # 再拉取私有仓库内的镜像
v1: Pulling from nginx
Digest:
sha256:ee89b00528ff4f02f2405e4ee221743ebc3f8e8dd0b
fd5c4c20a2fa2aaa7ede3
Status: Downloaded newer image for
192.168.15.3:5000/nginx:v1
192.168.15.3:5000/nginx:v1
[root@doc ~]# docker tag
192.168.15.3:5000/nginx:v1 nginx:v2 # 改名
[root@doc ~]# docker images # 查看所有镜像
REPOSITORY TAG IMAGE ID
CREATED SIZE7、其他主机上传
只要同在⼀个局域⽹内的所有主机都可向本地镜像仓库内上传镜
像,⽅法同上,在上传时只需注意:
当添加完参数后,就可向本地私有仓库上传。
busybox latest beae173ccac6
23 months ago 1.24MB
192.168.15.3:5000/nginx v1 605c77e624dd
23 months ago 141MB
nginx latest 605c77e624dd
23 months ago 141MB
nginx v2 605c77e624dd
23 months ago 141MB
registry latest b8604a3fe854
2 years ago 26.2MB
[root@doc ~]# vim
/usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --
containerd=/run/containerd/containerd.sock --
insecure-registry 192.168.15.3:5000 # 添加参数
[root@doc ~]# systemctl daemon-reload
[root@doc ~]# systemctl restart docker.service
Docker允许通过外部访问容器或者容器之间互联的⽅式来提供⽹络
服务。
容器启动之后,容器中可以运⾏⼀些⽹络应⽤,通过-p或-P参数来
指定端⼝映射。
宿主机的⼀个端⼝只能映射到容器内部的某⼀个端⼝上,⽐如:
8080->80之后,就不能8080->81。
容器内部的某个端⼝可以被宿主机的多个端⼝映射,⽐如: 8080-
>80,8090->80,8099->80。
⼀、为容器绑定宿主机端⼝
-p ⼩写p表示docker会选择⼀个具体的宿主机端⼝映射到容器
内部开放的⽹络端⼝上。
-P ⼤写P表示docker会随机选择⼀个宿主机端⼝映射到容器内
部开放的⽹络端⼝上。
[root@doc ~]# docker run -itd --name nginx1 -p
8080:80 nginx:latest
d9df73aa43cb496df80717f91170ea97912601fc25757cd4b7
125d3054f6d61a
[root@doc ~]# docker run -itd --name nginx2 -P
nginx:latest8cf5a8dce583990619ad38d847438564600edd490917d94fe4
cbd144ce7da195
[root@doc ~]# docker ps
CONTAINER ID IMAGE COMMAND
CREATED STATUS PORTS
NAMES
8cf5a8dce583 nginx:latest "/docker
entrypoint.…" 10 seconds ago Up 9 seconds
0.0.0.0:32768->80/tcp, :::32768->80/tcp
nginx2
d9df73aa43cb nginx:latest "/docker
entrypoint.…" 16 seconds ago Up 15 seconds
0.0.0.0:8080->80/tcp, :::8080->80/tcp
nginx1
9ab3d198bf05 registry:latest "/entrypoint.sh
/etc…" About an hour ago Up 48 minutes
0.0.0.0:5000->5000/tcp, :::5000->5000/tcp
registry
[root@doc ~]# netstat -anpt | grep 8080
tcp 0 0 0.0.0.0:8080
0.0.0.0:* LISTEN 9922/docker
proxy
tcp6 0 0 :::8080 :::*
LISTEN 9930/docker-proxy
[root@doc ~]# netstat -anpt | grep 32768访问本机地址:8080 即可访问到 nginx1 容器。
访问本机地址:32768 即可访问到 nginx2 容器,这是 -P 的随机映射
端⼝。
⼆、为容器绑定宿主机 IP
tcp 0 0 0.0.0.0:32768
0.0.0.0:* LISTEN 10046/docker
proxy
tcp6 0 0 :::32768 :::*
LISTEN 10052/docker-proxy[root@doc ~]# docker run -itd --name nginx3 -p
127.0.0.1:8888:80 nginx:latest
66347b8f5295247146ecfeeee4bf9cda313eb8b67c662a1fa0
7f10649c602ddf
[root@doc ~]# docker run -itd --name nginx4 -p
192.168.15.3:9999:80 nginx:latest
fd2c230b4c562e9531dd4e2208a59800284395e6afaa66eae6
41d75933442a1c
[root@doc ~]# docker ps
CONTAINER ID IMAGE COMMAND
CREATED STATUS PORTS
NAMES
fd2c230b4c56 nginx:latest "/docker
entrypoint.…" 3 seconds ago Up 2 seconds
192.168.15.3:9999->80/tcp
nginx4
66347b8f5295 nginx:latest "/docker
entrypoint.…" 10 seconds ago Up 9 seconds
127.0.0.1:8888->80/tcp
nginx3
访问 127.0.0.1:8888 即可访问到 nginx3 容器
访问 192.168.15.3:9999 即可访问到 nginx4 容器
但访问 192.168.15.3:8888 和 127.0.0.1:9999 就⽆法访问到
nginx三、容器指定通信协议
四、查看容器绑定端⼝和容器的 IP 地址
[root@doc ~]# docker run -itd --name nginx5 -p
7777:80/udp nginx:latest
9a90cd757d59de57c247543e9dda5d186798e12677e83239cd
28394e8424f467
[root@doc ~]# docker ps | grep nginx5
9a90cd757d59 nginx:latest "/docker
entrypoint.…" 16 seconds ago Up 15 seconds
80/tcp, 0.0.0.0:7777->80/udp, :::7777->80/udp
nginx5
[root@doc ~]# netstat -anpu | grep 7777
udp 0 0 0.0.0.0:7777
0.0.0.0:* 10998/docker
proxy
udp6 0 0 :::7777 :::*
11004/docker-proxy 五、错误处理
1、启动容器时报错
错误信息:
[root@doc ~]# docker port nginx4
80/tcp -> 192.168.15.3:9999 # 容器绑定宿主机的IP和端
⼝
[root@doc ~]# docker inspect nginx4 | grep
IPAddress
"SecondaryIPAddresses": null,
"IPAddress": "172.17.0.6", # 容器的
IP地址
"IPAddress": "172.17.0.6",
/usr/bin/docker-current: Error response from
daemon: driver failed programming external
connectivity on endpoint my-nginx
(db5a0edac68d1ea7ccaa3a1e0db31ebdf278076ef4851ee42
50221af6167f9ac): (iptables failed:
iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --
dport 8088 -j DNAT --to-destination
172.17.0.2:80 ! -i docker0: iptables: No
chain/target/match by that name.解决⽅案:
1. 重启 docker 服务:systemctl restart docker
2. 再 docker start $(docker ps -qa)
2、容器端⼝映射到宿主机后,外部⽆法访问宿主机绑定端
⼝
错误信息:
创建 docker 容器的时候,做了端⼝映射到宿主机,防⽕墙已关闭,
但是外部始终⽆法访问宿主机端⼝。
错误原因:
1. 这种情况基本就是因为宿主机没有开启路由转发功能,从⽽导致
外部⽹络访问宿主机对应端⼝是没能转发到 Docker Container
所对应的端⼝上。
2. 也可能是宿主机对应端⼝被占⽤。
解决⽅案:
1. 设置路由转发
在 Linux 中开启 ip 转发的内核参数为:net.ipv4.ip_forward,查看是
否开启 ip转发:# cat /proc/sys/net/ipv4/ip_forward // 0:未开启,1:已开启
======
打开ip转发功能, 下⾯两种⽅法都是临时打开ip转发功能!
# echo 1 > /proc/sys/net/ipv4/ip_forward
# sysctl -w net.ipv4.ip_forward=1
======
永久⽣效的ip转发
# vim /etc/sysctl.conf
net.ipv4.ip_forward = 1
# sysctl -p /etc/sysctl.conf // ⽴即⽣效
Linux 系统中也可以通过重启⽹卡来⽴即⽣效 (修改 sysctl.conf ⽂件
后⽣效)
1. 关闭被占⽤端⼝的服务或修改容器端⼝
# netstat -anpt | grep 占⽤端⼝确认端⼝冲突是哪个服务,可以选择关闭服务,也可以选择修改服
务端⼝
======
通过 docker 容器管理命令可以先将端⼝冲突的容器删除(docker
rm -f 容器名/ID),再通过 docker run -itd -p 命令重新指定,在删
除前要做好该容器的备份,以免数据丢失。
======
在指定容器的端⼝映射时,⼀定要确认好宿主机的端⼝是否已经被
占⽤,否则在真正的⽣产环境时,⼀旦处理起来,可能会造成⼀定
的数据损失。