镜像

这命令也很简单,run 的意思就是要启动一个容器

# docker run -d centos/httpd:latest

-d 参数里 d 是 Daemon 的首字母,也就是让容器在后台运行。最后一个参数 centos/httpd:latest 指定了具体要启动哪一个镜像,比如这里咱们启动的是 centos/httpd 这个镜像的 latest 版本。

其实,镜像就是一个特殊的文件系统。它提供了容器中程序执行需要的所有文件。具体来说,就是应用程序想启动,需要三类文件:相关的程序可执行文件、库文件和配置文件,这三类文件都被容器打包做好了。

Dockerfile

Dockerfile 的每一行,第一个大写的词都是 Dockerfile 专门定义的指令,也就是 FROM、RUN、COPY、ADD、CMD,这些指令都很基础,所以我们不做详细解释了,你可以参考 Dockerfile 的官方文档

# cat Dockerfile
FROM centos:8.1.1911
RUN yum install -y httpd
COPY file1 /var/www/html/
ADD  file2.tar.gz /var/www/html/
CMD ["/sbin/httpd", "-D", "FOREGROUND"]

下面这个命令中 -f ./Dockerfile 指定 Dockerfile 文件,-t registry/httpd:v1 指定了生成出来的镜像名,它的格式是"name:tag",这个镜像名也是后面启动容器需要用到的。

# docker build -t registry/httpd:v1 -f ./Dockerfile .

docker build 执行成功之后,我们再运行 docker images 这个命令,就可以看到生成的镜像了。

# docker images
REPOSITORY  TAG   IMAGEID  CREATED   SIZE
registry/httpd  v1  c682fc3d4b9a  4 seconds ago  277MB

我们运行下面这个 docker exec 命令,也就是执行 docker exec c5a9ff78d9c1 ps -ef ,可以看到 httpd 的服务进程正在容器的空间中运行。

# docker exec c5a9ff78d9c1 ps -ef

UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 01:59 ?        00:00:00 /sbin/httpd -D FOREGROUND
apache       6     1  0 01:59 ?        00:00:00 /sbin/httpd -D FOREGROUND
apache       7     1  0 01:59 ?        00:00:00 /sbin/httpd -D FOREGROUND
apache       8     1  0 01:59 ?        00:00:00 /sbin/httpd -D FOREGROUND
apache       9     1  0 01:59 ?        00:00:00 /sbin/httpd -D FOREGROUND

容器是什么

两个术语 Namespace 和 Cgroups

Namespace

容器内

# docker exec c5a9ff78d9c1 ps -ef

UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 01:59 ?        00:00:00 /sbin/httpd -D FOREGROUND
apache       6     1  0 01:59 ?        00:00:00 /sbin/httpd -D FOREGROUND
apache       7     1  0 01:59 ?        00:00:00 /sbin/httpd -D FOREGROUND
apache       8     1  0 01:59 ?        00:00:00 /sbin/httpd -D FOREGROUND
apache       9     1  0 01:59 ?        00:00:00 /sbin/httpd -D FOREGROUND

宿主机

# ps -ef | grep httpd

UID        PID  PPID  C STIME TTY          TIME CMD
root     20731 20684  0 18:59 ?        00:00:01 /sbin/httpd -D FOREGROUND
48       20787 20731  0 18:59 ?        00:00:00 /sbin/httpd -D FOREGROUND
48       20788 20731  0 18:59 ?        00:00:06 /sbin/httpd -D FOREGROUND
48       20789 20731  0 18:59 ?        00:00:05 /sbin/httpd -D FOREGROUND
48       20791 20731  0 18:59 ?        00:00:05 /sbin/httpd -D FOREGROUN




容器shm作用_容器shm作用


containerd是宿主机上的一个守护进程,用来建立容器。每建立一个容器,就会有一个shim进程,它是容器中init进程的父进程。

containerd 启动当容器的时候先会启动一个shim, 然后由shim运行runc去创建container. 这样相当于一个shim来管理一个container. shim作为container的“父进程”, 接管了容器的stdin/stdout, containerd服务出问题,不会影响到用户的container。

Namespace 尽管类型不同,其实都是为了隔离容器资源:

  • PID Namespace 负责隔离不同容器的进程
  • Network Namespace 又负责管理网络环境的隔离
  • Mount Namespace 管理文件系统的隔离。

Cgroups

Cgroups 可以对指定的进程做各种计算机资源的限制,比如限制 CPU 的使用率,内存使用量,IO 设备的流量等等。

了解几种比较常用的 Cgroups 子系统:

  1. CPU 子系统,用来限制一个控制组(一组进程,你可以理解为一个容器里所有的进程)可使用的最大 CPU。
  2. memory 子系统,用来限制一个控制组最大的内存使用量。
  3. pids 子系统,用来限制一个控制组里最多可以运行多少个进程。
  4. cpuset 子系统, 这个子系统来限制一个控制组里的进程可以在哪几个物理 CPU 上运行。

memory 子系统的限制参数最简单,所以下面我们就用 memory 子系统为例。

对于启动的每个容器,都会在 Cgroups 子系统下建立一个目录,在 Cgroups 中这个目录也被称作控制组,比如下图里的"docker-""docker-"等。然后我们设置这个控制组的参数,通过这个方式,来限制这个容器的内存资源。


容器shm作用_docker_02


在每个 Cgroups 子系统下,对应这个容器就会有一个目录 docker-c5a9ff78d9c1……这个容器的 ID 号,容器中所有的进程都会储存在这个控制组中 cgroup.procs 这个参数里。

我们把(2* 1024 * 1024 * 1024 = 2147483648)这个值,写入 memory Cgroup 控制组中的 memory.limit_in_bytes 里,这样设置后,cgroup.procs 里面所有进程 Memory 使用量之和,最大也不会超过 2GB。

# cd /sys/fs/cgroup/memory/system.slice/docker-c5a9ff78d9c1fedd52511e18fdbd26357250719fa0d128349547a50fad7c5de9.scope


# cat cgroup.procs
20731
20787
20788
20789
20791

# echo 2147483648 > memory.limit_in_bytes
# cat memory.limit_in_bytes
2147483648

简单总结

目前呢,你只需要先记住这两个技术的作用,Namespace 帮助容器来实现各种计算资源的隔离,Cgroups 主要限制的是容器能够使用的某种资源量。

docker stop

containerd会先向容器中的init进程发送SIGTERM,如果init进程注册了SIGTERM

handler(并且handler让进程退出了)那么整个容器就退出了,如果容器的init进程没有注册SIGTERM, 那么过30秒, containerd再向容器的init进程发送SIGKILL.

容器对应的memory cgroup 目录

docker inspect 4d3cf63512a2 | grep \"Pid\"
"Pid": 4384,

# cat /proc/4384/cgroup | grep memory

5:memory:/system.slice/docker-4d3cf63512a2b89c0982724a6c12cb9b69781676aa93ab4fb2060f47908c6b94.scope
-----------------
-bash-4.2# pwd
/sys/fs/cgroup/memory

-bash-4.2# find . -name *8c28cc9c5db8*
./system.slice/docker-8c28cc9c5db88bf08b6ccc79aed58b8ec4afaeb1ef7ff27aaabfa60229824c08.scope

基础镜像怎么做?

docker base image, 拿centos为例子,可以建一个目录,让后把需要的rpm 安装在这个目录下面,然后把目录打成一个tarball, 用docker import成为一个base image.