一、Docker 到底是什么?先把概念掰明白

第一次接触 Docker 时,我总把它和虚拟机混为一谈,直到看到 Docker 之父 Solomon Hykes 的比喻:Docker 就像传统的货运集装箱。货物(应用)装进集装箱,不管是货车、轮船还是火车(不同环境),都能无缝运输,这就是 Docker 的核心价值。

核心三要素

镜像(Image):只读模板,软件 + 依赖 + 配置

容器(Container):镜像运行实例

仓库(Repository):存放镜像的地方

1.1 为啥 Docker 能火?核心优势太能打

轻量级虚拟化:启动容器秒级响应,虚拟机要几分钟,差距肉眼可见;

环境一致性:开发机写的代码,打包成容器扔到生产环境,再也不会出现 “我本地能跑啊” 的尴尬;

资源利用率拉满:多个容器共享宿主机内核,单机能跑上千个容器,虚拟机撑死几十个;

移植性拉满:本地、云服务器、私有集群,容器随便挪,不用改配置。

1.2 别再混淆!Docker vs 传统虚拟机

做了张对比表,一眼看清区别:

维度 虚拟机 Docker 容器
操作系统 宿主机上跑独立 OS 共享宿主机 OS 内核
镜像体积 GB 级 MB 级
性能 有 OS 额外资源消耗 几乎无性能损耗
部署速度 分钟级 秒级
运行密度 单机几十台 单机上千个容器

二、手把手部署 Docker

2.1 配置软件仓库

cd /etc/yum.repos.d
vim docker.repo
[docker]
name=docker-ce
baseurl=https://mirrors.aliyun.com/docker-ce/linux/rhel/9/x86_64/stable
gpgcheck=0

安装并启动 Docker

# 安装docker-ce
yum install -y docker-ce 

# 修复网络模式(默认nftables换成iptables)
vim /usr/lib/systemd/system/docker.service
# 找到ExecStart行,追加--iptables=true
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --iptables=true

# 开机自启并启动
systemctl enable --now docker
# 验证是否启动成功
docker info

优化网络配置

# 加载内核模块
echo br_netfilter > /etc/modules-load.d/docker_mod.conf
modprobe br_netfilter

# 配置内核参数
vim /etc/sysctl.d/docker.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1

# 生效配置并重启Docker
sysctl --system
systemctl restart docker

配置镜像加速器

vim /etc/docker/daemon.json
{
    "registry-mirrors": ["https://docker.m.daocloud.io"]
}
systemctl restart docker
# 验证加速器是否生效
docker info | grep "Registry Mirrors"

到这一步,Docker 就部署完成了,接下来练点实际的 —— 镜像和容器操作。

三、Docker 核心操作:镜像和容器玩明白

Docker 的核心是 “镜像” 和 “容器”,镜像就是 “安装包”,容器就是 “运行中的程序”,先把这俩玩溜。

3.1 镜像管理:搜、拉、看、导、删

① 搜索镜像

# 搜nginx镜像
docker search nginx

② 拉取镜像

# 拉取最新版nginx
docker pull nginx
# 拉取指定版本
docker pull nginx:1.26-alpine

③ 查看镜像

# 列出本地所有镜像
docker images
# 查看镜像详细信息
docker image inspect nginx:1.26-alpine
# 查看镜像构建历史(排查体积问题超有用)
docker history nginx:latest

④导出 / 导入镜像

# 导出单个镜像
docker save nginx:latest -o nginx-latest.tar.gz
# 导出多个镜像
docker save nginx:latest nginx:1.26-alpine -o nginx-tags.tar.gz
# 导入镜像
docker load -i nginx-latest.tar.gz

⑤ 删除镜像

# 删除单个镜像
docker rmi nginx:latest
# 批量删除所有镜像(谨慎用!)
docker rmi `docker images | awk 'NR>1{print $1":"$2}'`

3.2 容器操作:启、查、停、删、传

① 启动容器

# 后台运行nginx,映射80端口,命名为web
docker run -d --name web -p 80:80 nginx
# 交互式启动centos7(测试用)
docker run -it --name centos7 centos:7
# 退出容器:ctrl+d(停止容器)/ ctrl+p+q(不停止)

关键参数说明:

-d:后台运行

-it:交互式 + 终端

--name:指定容器名

-p:端口映射(宿主机:容器)

--rm:容器停止后自动删除

② 查看容器

# 查看运行中的容器
docker ps
# 查看所有容器(包括停止的)
docker ps -a
# 查看容器详细信息(比如IP、挂载)
docker inspect web(容器名)

③ 停止 / 启动容器

# 停止容器
docker stop web
# 强制停止(相当于kill)
docker kill web
# 启动停止的容器
docker start web

④ 删除容器

# 容器→宿主机(把web容器的index.html复制到/mnt)
docker cp web:/usr/share/nginx/html/index.html /mnt
# 宿主机→容器(把本地文件复制到web容器)
docker cp /mnt/test.html web:/usr/share/nginx/html/

⑤ 容器和宿主机传文件

# 容器→宿主机(把web容器的index.html复制到/mnt)
docker cp web:/usr/share/nginx/html/index.html /mnt
# 宿主机→容器(把本地文件复制到web容器)
docker cp /mnt/test.html web:/usr/share/nginx/html/

⑥ 查看容器日志

docker logs web(日志名)
# 实时查看日志
docker logs -f web

四、构建 Docker 镜像

指令 作用 示例
FROM 指定基础镜像 FROM centos:7
COPY 复制文件到容器 COPY index.html /usr/share/nginx/html
ADD 复制 + 解压 / 下载 ADD test.tar.gz /mnt
ENV 设置环境变量 ENV NAME=lee
RUN 构建时执行命令 RUN yum install -y nginx
WORKDIR 设置工作目录 WORKDIR /mnt
EXPOSE 声明端口(仅标识,不映射) EXPOSE 80
CMD 容器启动时执行(可被覆盖) CMD ["nginx", "-g", "daemon off;"]
ENTRYPOINT 容器启动时执行(不可被覆盖) ENTRYPOINT ["echo", "hello"]

① 准备构建目录和文件

mkdir docker-nginx && cd docker-nginx
# 下载nginx源码包(也可以用官方镜像改造)
wget https://nginx.org/download/nginx-1.23.3.tar.gz

② 编写 Dockerfile

# 多阶段构建:先编译,再精简
FROM centos:7 AS build
ADD nginx-1.23.3.tar.gz /mnt
WORKDIR /mnt/nginx-1.23.3
# 安装依赖+编译+清理
RUN yum install -y gcc make pcre-devel openssl-devel && \
    sed -i 's/CFLAGS="$CFLAGS -g"/#CFLAGS="$CFLAGS -g"/g' auto/cc/gcc && \
    ./configure --with-http_ssl_module && \
    make && make install && \
    rm -fr /mnt/nginx-1.23.3 && yum clean all

# 精简镜像:只复制编译好的nginx
FROM centos:7
COPY --from=build /usr/local/nginx /usr/local/nginx
EXPOSE 80
CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]

③ 构建镜像

docker build -t mynginx:v1 .
④ 优化镜像体积(重点!)

刚构建的镜像可能几百 MB,优化思路:

  1. 选轻量基础镜像(比如 alpine、distroless);
  2. 减少镜像层数(RUN 指令用 && 合并);
  3. 多阶段构建(编译和运行分离);
  4. 清理构建残留(yum clean all、rm -fr)。

优化后我的 mynginx 镜像从 494MB 降到 205MB,换成 distroless 基础镜像后只剩 34MB!

五、Docker 网络

5.1 Docker 网络基础原理

Docker 的网络子系统实现了容器间、容器与宿主机、容器与外部网络的通信能力,其核心是基于 Linux 网络命名空间(Network Namespace)实现网络隔离,同时通过虚拟网桥、veth pair 等技术构建通信链路。

5.1.1 Docker 默认网络模式

Docker 安装后会默认创建 3 种网络模式,可通过docker network ls查看:

网络模式 特点 适用场景
bridge(桥接网络) 默认模式,容器接入 docker0 网桥,通过 NAT 与外部通信 单主机内容器间通信、容器访问外网
host(主机网络) 容器共享宿主机网络命名空间,无端口映射开销 对网络性能要求高、需直接使用宿主机端口的场景
none(无网络) 容器仅有 lo 回环接口,无外部网络连接 仅需本地进程通信、无需网络的场景

5.1.2 自定义网络(推荐)

默认 bridge 网络存在容器间只能通过 IP 通信、无法解析容器名的问题,自定义网络可解决该问题,同时支持更灵活的配置:

# 创建自定义桥接网络
docker network create --driver bridge my-bridge-network

# 启动容器时指定自定义网络
docker run -d --name nginx-1 --network my-bridge-network nginx:latest

# 容器运行时接入自定义网络
docker network connect my-bridge-network nginx-2

# 验证:自定义网络内容器可通过容器名ping通
docker exec -it nginx-1 ping nginx-2

5.2 端口映射(容器对外通信)

通过端口映射可将容器内端口暴露到宿主机,实现外部访问容器服务:

# 格式:-p 宿主机端口:容器端口(可指定宿主机IP)
# 示例1:宿主机8080端口映射到容器80端口
docker run -d --name nginx-web -p 8080:80 nginx:latest

# 示例2:指定宿主机IP(192.168.1.100)的8080端口映射到容器80端口
docker run -d --name nginx-web -p 192.168.1.100:8080:80 nginx:latest

# 示例3:随机映射宿主机端口(docker会分配未使用的高位端口)
docker run -d --name nginx-web -P nginx:latest

5.3 容器间网络通信

同一网络内通信:自定义网络中容器可通过容器名 / 别名直接通信,无需 IP;

跨网络通信:通过docker network connect将容器接入多个网络,实现跨网络通信;

容器访问宿主机:Docker 默认将宿主机 IP 映射到容器内host.docker.internal(Linux 需手动配置),或直接使用宿主机网桥 IP(如 172.17.0.1)。

六、Docker 仓库配置

搭建简单的Registry仓库

[root@docker ~]# docker pull registry
Using default tag: latest
latest: Pulling from library/registry
930bdd4d222e: Pull complete
a15309931e05: Pull complete
6263fb9c821f: Pull complete
86c1d3af3872: Pull complete
a37b1bf6a96f: Pull complete
Digest: sha256:12120425f07de11a1b899e418d4b0ea174c8d4d572d45bdb640f93bc7ca06a3d
Status: Downloaded newer image for registry:latest
docker.io/library/registry:latest

开启Registry

[root@docker ~]# docker run  -d -p 5000:5000 --restart=always --name registry registry
bc58d3753a701ae67351fac335b06a4d7f66afa10ae60b992f647117827734c5
[root@docker ~]# docker ps
CONTAINER ID   IMAGE      COMMAND                   CREATED         STATUS         PORTS            NAMES
bc58d3753a70   registry   "/entrypoint.sh /etc…"   7 seconds ago   Up 6 seconds   5000/tcp, 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   registry

上传镜像到仓库中

#给要上传的经镜像大标签
[root@docker ~]# docker tag busybox:latest  172.25.254.100:5000/busybox:latest

#docker在上传的过程中默认使用https,但是我们并没有建立https认证需要的认证文件所以会报错
[root@docker ~]# docker push 172.25.254.100:5000/busybox:latest
The push refers to repository [172.25.254.100:5000/busybox]
Get "https://172.25.254.100:5000/v2/": dial tcp 172.25.254.100:5000: connect: connection refused


#配置非加密端口
[root@docker ~]# vim /etc/docker/daemon.json
{
  "insecure-registries" : ["http://172.25.254.100:5000"]
}

[root@docker ~]# systemctl restart docker

#上传镜像
[root@docker ~]# docker push  172.25.254.100:5000/busybox:latest
The push refers to repository [172.25.254.100:5000/busybox]
d51af96cf93e: Pushed
latest: digest: sha256:28e01ab32c9dbcbaae96cf0d5b472f22e231d9e603811857b295e61197e40a9b size: 527

#查看镜像上传
[root@docker ~]# curl 172.25.254.100:5000/v2/_catalog
{"repositories":["busybox"]}

为Registry提加密传输

#生成认证key和证书
[root@docker ~]#  openssl req -newkey  rsa:4096 \
-nodes -sha256 -keyout certs/timinglee.org.key \
-addext "subjectAltName = DNS:reg.timinglee.org" \		#指定备用名称
-x509 -days 365 -out certs/timinglee.org.crt

You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Shaanxi
Locality Name (eg, city) [Default City]:Xi'an
Organization Name (eg, company) [Default Company Ltd]:timinglee
Organizational Unit Name (eg, section) []:docker
Common Name (eg, your name or your server's hostname) []:reg.timinglee.org
Email Address []:admin@timinglee.org

#查看证书信息
[root@docker-node1 ~]# openssl x509 -in certs/timinglee.org.crt -noout -text
#启动registry仓库
[root@docker ~]# docker run -d -p 443:443 --restart=always --name registry \
-v /opt/registry:/var/lib/registry \
-v /root/certs:/certs \
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/timinglee.org.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/timinglee.org.key registry

测试:

[root@docker docker]# docker push reg.timinglee.org/busybox:latest		#docker客户端没有key和证书
Error response from daemon: Get "https://reg.timinglee.org/v2/": tls: failed to verify certificate: x509: certificate signed by unknown authority

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐