Docker 是一个开源的容器化平台,可以用来打包、分发和运行应用程序。
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何机器上,进而实现快速部署。
本文介绍 Docker 的基本概念、安装方法和常用命令,以及如何使用 Docker 部署应用程序。
安装 Install using script 1 2 curl -fsSL https://get.docker.com -o install-docker.sh sudo sh install-docker.sh
Install using apt 1 2 sudo apt-get updatesudo apt-get install docker.io
Install from package
访问这里 ,找到相应的版本(amd64, arm64…)。
下载下面这些 deb 包:
containerd.io_<version>_<arch>.deb
docker-ce-cli_<version>_<arch>.deb
docker-ce_<version>_<arch>.deb
docker-buildx-plugin_<version>_<arch>.deb
docker-compose-plugin_<version>_<arch>.deb
安装:1 sudo dpkg -i containerd.io_<version>_<arch >.deb docker-ce-cli_<version>_<arch >.deb docker-ce_<version>_<arch >.deb docker-buildx-plugin_<version>_<arch >.deb docker-compose-plugin_<version>_<arch >.deb
安装完成后可以运行下面的命令检查是否安装成功:
1 2 docker version docker info
Docker 是 C/S 架构,命令行客户端通过 Socket 连接到服务端,而服务端则是一个本机守护进程。运行 Docker 命令的时候需要本机有 Docker 服务,如果使用 docker info 命令时显示无 Server 进程在运行,可以通过下面的命令启动 Docker 服务:
1 2 sudo service docker startsudo systemctl start docker
Docker 进程使用 Unix Socket 通信,而默认情况下,Unix Socket属于 root 用户,需要 root 权限才能访问。 使用 docker ps 命令若显示 Permission denied,则需要使用 sudo 运行或者通过下面的命令将当前用户加入 docker 用户组:
1 2 3 4 sudo groupadd docker sudo gpasswd -a $USER docker newgrp docker docker ps
由于Docker Hub被 DNS 污染,国内各镜像源近期发布公告 停止Docker Hub的镜像同步,此处推荐使用代理工具,更新 docker.service 文件(/lib/systemd/system/docker.service),添加代理配置:
1 2 3 [Service] Environment="HTTP_PROXY=http://127.0.0.1:7890" Environment="HTTPS_PROXY=http://127.0.0.1:7890"
原理 Docker 是轻量级虚拟化的一种形式,它将运行于同一内核的进程组从环境上彼此隔离,就像运行在不同的机器上一样,为了实现 Docker,内核开发者为内核中的各种全局系统资源(如进程ID、网络协议栈、文件系统等)提供一个间接层,以便每个容器能为这些资源提供各自的实例。
具体来说,Docker 其实就通过 Linux 内核中的 Namespaces 对不同的容器实现了隔离,并通过 clone() 等系统调用创建新进程的同时创建新的 Namespace,从而实现了容器的隔离。
Namespace Namespace 是 Linux 内核提供的一种系统资源隔离机制,它可以将全局系统资源封装在一个独立的 Namespace 环境中,使得不同 Namespace 中的进程可以拥有各自独立的资源实例,互不干扰,常见的 Namespace 有:
名称
宏定义
隔离内容
IPC
CLONE_NEWIPC
实现容器与宿主机、容器与容器之间的IPC隔离,包括信号量、消息队列和共享内存
Network
CLONE_NEWNET
提供网络资源的隔离,包括网络设备、IPv4和IPv6协议栈、IP路由表、防火墙、套接字等
Mount
CLONE_NEWNS
实现隔离文件系统挂载点,使容器内有独立的挂载文件系统
PID
CLONE_NEWPID
实现容器内有独立的进程树(也就意味着每个容器都有自己的PID为1的进程)
User
CLONE_NEWUSER
实现用户可将不同的主机用户映射到容器,比如user用户映射到容器内的root用户上
UTS
CLONE_NEWUTS
实现容器可以拥有独立的主机名和域名,在网络上可以视为独立的节点
Cgroup
CLONE_NEWCGROUP
实现资源的限制(CPU、Memory等等)
clone() clone() 是 Linux 特有的系统调用,可以通过它来创建一个独立 Namespace 的进程,这个进程被称为子进程。 clone() 创建新进程类似于 fork() 和 vfork(),但可以选择性地共享父进程的资源,通过传递不同的参数可以实现不同的功能,在进程创建期间对步骤的控制相比前者也更加灵活。
1 2 3 4 5 6 #include <sched.h> int clone (int (*func)(void *), void *child_stack, int flags, void *func_arg, ... ) ;
标志
设置后的效果
CLONE_CHILD_CLEARTID
当子进程调用 exec()或_exit()时,清除 ctid(从版本 2.6 开始)
CLONE_CHILD_SETTID
将子进程的线程 ID 写入 ctid(从 2.6 版本开始)
CLONE_FILES
父、子进程共享打开文件描述符表
CLONE_FS
父、子进程共享与文件系统相关的属性
CLONE_IO
子进程共享父进程的 I/O 上下文环境(从 2.6.25 版本开始)
CLONE_NEWIPC
子进程获得新的 System V IPC 命名空间(从 2.6.19 开始)
CLONE_NEWNET
子进程获得新的网络命名空间(从 2.4.24 版本开始)
CLONE_NEWNS
子进程获得父进程挂载(mount)命名空间的副本(从 2.4.19 版本开始)
CLONE_NEWPID
子进程获得新的进程 ID 命名空间(从 2.6.23 版本开始)
CLONE_NEWUSER
子进程获得新的用户 ID 命名空间(从 2.6.23 版本开始)
CLONE_NEWUTS
子进程获得新的 UTS(utsname())命名空间(从 2.6.19 版本开始)
CLONE_PARENT
将子进程的父进程置为调用者的父进程(从 2.4 版本开始)
CLONE_PARENT_SETTID
将子进程的线程 ID 写入 ptid(从 2.6 版本开始)
CLONE_PID
标志已废止,仅用于系统启动进程(直至 2.4 版本为止)
CLONE_PTRACE
如果正在跟踪父进程,那么子进程也照此办理
CLONE_SETTLS
tls 描述子进程的线程本地存储(从 2.6 开始)
CLONE_SIGHAND
父、子进程共享对信号的处置设置
CLONE_SYSVSEM
父、子进程共享信号量还原(undo)值(从 2.6 版本开始)
CLONE_THREAD
将子进程置于父进程所属的线程组中(从 2.4 开始)
CLONE_UNTRACED
不强制对子进程设置 CLONE_PTRACE(从 2.6 版本开始)
CLONE_VFORK
挂起父进程直至子进程调用 exec()或_exit()
CLONE_VM
父、子进程共享虚拟内存
除了 clone() 系统调用外,Docker 还使用 setns() 系统调用来将进程加入到指定的 Namespace 中,以及 unshare() 系统调用来撤创建的子进程对某个 Namespace 的隔离,具体可以参考这里 进行了解。
cgroups 控制组 Cgroups 是一种 Linux 内核功能,用于限制、计量和隔离进程组的资源使用,如 CPU、内存、磁盘 I/O 和网络带宽。Docker 利用控制组来管理和限制容器的资源使用,确保容器之间不会相互干扰,并且能够有效利用系统资源。
命令 镜像 镜像(image)可以理解成一个虚拟机的快照(snapshot),包含要运行的应用程序以及与它相关的所有环境配置和依赖库。镜像是只读的,不可修改,所有的修改都是在容器层面进行的,通过镜像可以创建多个容器实例。
1 2 3 4 5 6 7 8 9 10 docker pull <image_name>[:tag] docker images docker rmi <image_name> docker build -t <image_name> . docker build -t <image_name> . -no-cache docker commit -m "msg" -a "auth" <container_id> <image_name> docker save <image_name> > <image_name>.tar docker load < <image_name>.tar docker tag <image_id> <new_image_name>[:tag] docker image prune
容器 容器(container)是镜像的一个实例,是一个独立运行的应用程序,包含了应用程序的代码、运行时环境、系统工具、系统库和设置。容器是可读可写的,可以在容器内部进行修改,但不会影响到镜像。
1 2 3 4 5 6 7 8 9 10 11 12 13 docker run --name <container_name> <image_name> docker run -p <host_port>:<container_port> <image_name> docker cp <container_name>:<container_path> <host_path> docker run -d <image_name> docker start|stop|restart <container_name> docker rm <container_name> docker exec -it <container_name> /bin/bash docker inspect <container_name> docker logs <container_name> docker ps docker ps -a docker top <container_name> docker container stats <container_name>
仓库 仓库(repository)类似代码仓库,是集中存放镜像文件的场所。全球最大的公开仓库是 Docker Hub ,存放了数量庞大的镜像供用户下载。
1 2 3 4 docker login -u <username> docker push <username>/<image_name>[:tag] docker pull <username>/<image_name>[:tag] docker search <image_name>
通用 1 2 3 docker --help docker version docker info
实践 拉取镜像 1 2 3 4 5 6 ➜ docker pull ubuntu:20.04 20.04: Pulling from library/ubuntu d9802f032d67: Pull complete Digest: sha256:8e5c4f0285ecbb4ead070431d29b576a530d3166df73ec44affc1cd27555141b Status: Downloaded newer image for ubuntu:20.04 docker.io/library/ubuntu:20.04
通过镜像创建容器并运行 1 2 3 4 5 6 7 ➜ docker run -itd \ --name ubuntu-2004-dev \ --restart always \ ubuntu:20.04 \ /bin/bash root@d6b193ffbbbc:/# cat /etc/issue Ubuntu 20.04.6 LTS \n \l
-i -t: 保持标准输入打开并分配一个伪终端,确保容器内的 bash 不会因为没有交互而立即退出。 -d: Detached,让容器在后台持续运行。 –restart always: 设置容器自动重启,无论容器是因为进程崩溃退出,还是因为宿主机重启,Docker 守护进程都会自动重新启动该容器。
配置开发环境 1 2 3 root@d6b193ffbbbc:/# apt update && apt-get update root@d6b193ffbbbc:/# apt install curl gcc g++ cmake gdb vim git iputils-ping -y root@d6b193ffbbbc:/# curl -LsSf https://astral.sh/uv/install.sh | sh
保存容器为镜像 1 2 ➜ docker commit -m "build dev env" -a "xiejunjie" d6b193ffbbbc ubuntu_2004_dev_env sha256:a111489c0103ba6b8b630dfd4d48a956b41ee54e45fe4f5a5e182533f11c469d
-m 选项用于指定提交的描述信息,-a 选项用于指定提交的作者信息,d6b193ffbbbc 是容器的 ID,ubuntu_2004_dev_env 是新镜像的名称。
查看镜像 1 2 3 4 ➜ docker images REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu_2004_dev_env latest a111489c0103 5 minutes ago 596MB ubuntu 20.04 6013ae1a63c2 8 weeks ago 72.8MB
可以看到新创建的镜像 SIZE 比原始的镜像大了很多,这是因为新镜像包含了开发环境的配置。
打包镜像 1 ➜ docker save ubuntu_2004_dev_env > ~/HelloDocker/ubuntu_2024_dev_env.tar
加载镜像 1 ➜ docker load < ~/HelloDocker/ubuntu_2024_dev_env.tar
上传镜像 1 2 ➜ docker tag ubuntu_2004_dev_env xiejunjie/ubuntu_2004_dev_env:latest ➜ docker push xiejunjie/ubuntu_2004_dev_env:latest
参考