Docker 零基础完整实操手册:镜像、容器、数据卷、网络、Compose、Dockerfile
目录
镜像管理
拉取镜像
命令
docker pull 镜像名称
例子:需要上外网
docker pull busybox
# 默认情况下,直接拉取镜像会报错,原因是因为网络问题,可以选择配置华为云加速器
配置华为云加速器
vim /etc/docker/daemon.json
{ "registry-mirrors": [ "https://0aa309b95880f35a0fcfc00928b5d700.mirror.swr.myhuaweicloud.com" ] }
配置完后
systemctl daemon-reload
systemctl restart docker.service
docker pull busybox
docker images #查看所有拉取的镜像
镜像名称规则
仓库地址:镜像仓库地址,默认是Docker Hub,不写也行
命名空间/组织:类似于 GitHub 的用户或组织名,Docker Hub 上默认是 library
镜像名:镜像的核心名称,如nginx、ubuntu
标签(Tag):表示镜像的版本,不写默认为 latest
如果镜像没有指定仓库地址和命名空间以及版本,例如:docker pull nginx, 那么docker会从它自己的dockerhub中拉取(默认地址)最新版本的tag。
镜像列举
docker images
docker image list
docker image ls
镜像的保存与载入
保存
docker save 镜像1 镜像2 镜像3 -o xxx.tar
docker save busybox:latest apine:latest -o xxx.tar
载入
docker load -i xxx.tar
镜像的删除
docker rmi 镜像名称
例如:docker rmi alpine
容器的关闭/启动/重启
[root@docker01 ~]# docker stop os3
os3
[root@docker01 ~]# docker stop os2 os1
os2
os1
docker start name
docker restart name
创建(运行)一个MySQL容器
docker run -tid --name db mysql:5.7
-t 指定终端交互
-i 指定容器交互
-d 指定容器参数
查询容器
进入容器exec -ti
先创建容器
[root@docker01 ~]# docker run -tid --name os1 centos:7.9
ae2e97e02ca13e5b0fbf694f9ac172d15d0a9e3904e018a77c4129eaf6440c6e
[root@docker01 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ae2e97e02ca1 centos:7.9 "/bin/bash" 24 seconds ago Up 23 seconds os1
[root@docker01 ~]# docker exec -ti os1 /bin/bash
[root@ae2e97e02ca1 /]# ls
anaconda-post.log bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
[root@ae2e97e02ca1 /]# exit
exit
[root@docker01 ~]# docker run -tid --name os2 alpine:3.22
cb726fb4e5e9035d3cabb772cec8efbc1a7793f395ec6dde6744595f8f1b4925
[root@docker01 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cb726fb4e5e9 alpine:3.22 "/bin/sh" 7 seconds ago Up 7 seconds os2
ae2e97e02ca1 centos:7.9 "/bin/bash" 3 minutes ago Up 3 minutes os1
[root@docker01 ~]# docker exec -ti os2 /bin/sh
/ # ls
bin dev etc home lib media mnt opt proc root run sbin srv sys tmp usr var
查询容器日志logs
[root@docker01 ~]# docker logs db
2026-07-22 15:56:54+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.44-1.el7 started.
2026-07-22 15:56:55+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2026-07-22 15:56:55+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.44-1.el7 started.
2026-07-22 15:56:55+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified
You need to specify one of the following as an environment variable:
- MYSQL_ROOT_PASSWORD
- MYSQL_ALLOW_EMPTY_PASSWORD
- MYSQL_RANDOM_ROOT_PASSWORD
创建mysql的时候,需要为MySQL指定root的密码
指定容器环境变量 -e
[root@docker01 ~]# docker run -tid --name mysql8 -e MYSQL_ROOT_PASSWORD=123456 mysql8.4:latest
fdd39d448248014e5eabdef3d40a932fb19d5b15590da080739d28b475cc81d7
[root@docker01 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fdd39d448248 mysql8.4:latest "docker-entrypoint.s…" 8 seconds ago Up 8 seconds 3306/tcp, 33060/tcp mysql8
mysql容器能正常运行了,是如何进行连接呢?首先需要知道MySQL容器的IP地址
查询容器详细信息inspect
[root@docker01 ~]# docker inspect db |grep -i ipaddr
error: no such object: db
[root@docker01 ~]# docker inspect mysql8 |grep -i ipaddr
"IPAddress": "172.17.0.2",
尝试登陆MySQL
[root@docker01 ~]# docker exec -ti mysql8 /bin/bash
bash-5.1# mysql -uroot -p123456 -h 172.17.0.2
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.4.5 MySQL Community Server - GPL
Copyright (c) 2000, 2025, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
4 rows in set (0.00 sec)
那我们如何使用远程连接工具去连接容器MySQL呢?是使用虚拟机地址呢?还是MySQL容器的IP地址呢?其实都不是。原理如下
指定容器端口 -p
docker run -tid --name db -e MYSQL_ROOT_PASSWORD=123456 -p 33306:3306 mysql:8.4
docker ps
容器跑起来了在使用远程登陆
yum install -y mariadb
mysql -uroot -p123456 -h 172.17.0.2
使用docker快速构建wordpress博客
docker pull registry.cn-hangzhou.aliyuncs.com/tianhairui/wordpress:6.8.1
docker pull registry.cn-hangzhou.aliyuncs.com/tianhairui/mysql:8.4.5
# tag 创建新的镜像名称 docker tag registry.cn-hangzhou.aliyuncs.com/tianhairui/wordpress:6.8.1 wordpress:latest docker tag registry.cn-hangzhou.aliyuncs.com/tianhairui/mysql:8.4.5 mysql:latest
#删除之前的镜像
docker rmi $(docker images -qa)
创建MySQL
docker run -tid --name db -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=wordpress mysql:latest
docker inspect db |grep -i ipaddr
"SecondaryIPAddresses": null,
"IPAddress": "172.17.0.2",
"IPAddress": "172.17.0.2",
mysql -uroot -p123456 -h 172.17.0.2
创建wordpress
docker run -tid --name web -e WORDPRESS_DB_HOST=172.17.0.2 -e WORDPRESS_DB_USER=root -e WORDPRESS_DB_PASSWORD=123456 -e WORDPRESS_DB_NAME=wordpress -p 8080:80 wordpress:latest
镜像推送
我们可以自己在华为云或者阿里云上创建一个镜像站,之后的话自己可以从镜像站里拉取(docker pull),那步骤呢?
以华为云为例:SWR容器镜像服务
总结三步骤:
- docker login
- docker tag
- docker push
# login
[root@docker ~]# docker login --username=clisxxxxx@126.com registry.cn-hangzhou.aliyuncs.com
Password:
WARNING! Your credentials are stored unencrypted in '/root/.docker/config.json'.
Configure a credential helper to remove this warning. See
https://docs.docker.com/go/credential-store/
Login Succeeded
# tag
[root@docker ~]# docker tag alpine:latest registry.cn-hangzhou.aliyuncs.com/gcontainer/test:aaa
# push
[root@docker ~]# docker push registry.cn-hangzhou.aliyuncs.com/gcontainer/test:aaa
将容器提交成镜像commit
[root@docker ~]# docker commit os1 alpine:new
sha256:4f4edfa81bbe1821439c49e01e2e6ea61e84aa8c61ae7e8598ef2e8fd51c13d3
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine new 4f4edfa81bbe 5 seconds ago 8.31MB
将容器导出并导入镜像export/import
[root@docker ~]# docker export -o alpine.tar os1
[root@docker ~]# ls
666.txt alpine.tar anaconda-ks.cfg busyalpi.tar my.cnf mysql_ps
[root@docker ~]# docker import alpine.tar test:v2.0
sha256:5ebc60ab5ca1bfd53b175f6629ce973ac5d67ccf13796736bb22a212507b26cc
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
test v2.0 5ebc60ab5ca1 2 seconds ago 8.31MB
容器卷管理
容器层目录(临时卷)
临时卷指的是使用的容器层目录,会随着容器的删除而删除。
先创建容器
[root@docker01 ~]# docker run -tid --name os1 centos:7.9
e943efa91d9d1a2b34a5b44231b4d4dffddc2ceab2a1c2d390eb2e22f902af4b
进入容器
[root@docker01 ~]# docker exec -ti os1 /bin/bash
[root@e943efa91d9d /]# mkdir /abc
[root@e943efa91d9d /]# cd /abc
[root@e943efa91d9d abc]# ls
[root@e943efa91d9d abc]# touch {a,b,c}{1,2,3}.txt
[root@e943efa91d9d abc]# ls
a1.txt a2.txt a3.txt b1.txt b2.txt b3.txt c1.txt c2.txt c3.txt
[root@e943efa91d9d abc]# exit
exit
退出容器查找所创建的目录
[root@docker01 ~]# find / -name a1.txt
/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/308/fs/abc/a1.txt
/var/lib/docker/rootfs/overlayfs/e943efa91d9d1a2b34a5b44231b4d4dffddc2ceab2a1c2d390eb2e22f902af4b/abc/a1.txt
[root@docker01 ~]# find / -name a2.txt
/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/308/fs/abc/a2.txt
/var/lib/docker/rootfs/overlayfs/e943efa91d9d1a2b34a5b44231b4d4dffddc2ceab2a1c2d390eb2e22f902af4b/abc/a2.txt
Overlayfs在镜像分层有说明
物理层目录(永久卷)
默认情况下,容器写入的数据,会被保存在容器层,随着容器删除而删除;这时候可以将容器文件和物理主机某个文件进行绑定映射。
创建映射卷有两种方法:
-v /data --仅指定容器目录,物理机会随机分配目录进行映射
-v /host_data:/data --左边指定物理机目录,右边指定容器目录,进行映射
[root@docker01 ~]# docker run -tid --name os1 -v /aaa centos:7.9
626741698a6c479d402178736b4003e0d50d1044f26a30b1c40fa208544acdf7
[root@docker01 ~]# docker exec -ti os1 /bin/bash
[root@626741698a6c /]# ls
aaa anaconda-post.log bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
[root@626741698a6c /]# cd /aaa
[root@626741698a6c aaa]# touch aaa.txt
[root@626741698a6c aaa]# exit
exit
[root@docker01 ~]# find / -name aaa.txt
find: ‘/proc/12686’: No such file or directory
/var/lib/docker/volumes/a367c5fb59eb08f69634cf1a15957f4f101f73aac3e7ef085b6f144c4fc153ac/_data/aaa.txt
/host_aaa/aaa.txt
你会发现,其实这种方式不太方便去寻找数据,我们可以采用另外一种方式,手工指定映射目录,例如:
[root@docker01 ~]# docker run -tid --name os2 -v /aaa:/bbb centos:7.9
1ccf8e4dd683e1afaf3b40bd1f9693bcbf75a12e94e598aacef76d21b8cfad09
[root@docker01 ~]# docker exec -ti os
os1 os2
[root@docker01 ~]# docker exec -ti os2 /bin/bash
[root@1ccf8e4dd683 /]# ls
anaconda-post.log bbb bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
[root@1ccf8e4dd683 /]# cd /bbb
[root@1ccf8e4dd683 bbb]# touch a b c d e
[root@1ccf8e4dd683 bbb]# ls
a b c d e
[root@1ccf8e4dd683 bbb]# exit
exit
在虚拟机上查看数据,不是容器上
[root@docker01 ~]# ls /aaa/
a b c d e
注意:最后删除容器并观察底层数据
[root@docker01 ~]# docker rm -f os2
os2
[root@docker01 ~]# ls /aaa/
a b c d e
网络管理
容器互联管理Link
Link主要解决因容器关闭,从而导致下次启动的时候ip地址发生变化
网络管理
总结:
bridge 类型相当于vmware NAT ,可以上外网;
host 类型直接复用了主机网络(共享),可以上外网;
none 没有虚拟网卡,适用于构建封闭环境进行安全测试。
注意:这里暂不讨论跨节点互通,后续可通过Docker Swarm或Kubernetes网络插件实现。
macvlan 要保证和宿主机位于同一个网段,每个容器都会有自己的mac地址,纯二层网络
ipvlan 即可以是二层,也支持三层,所有容器共用一个mac地址。
overlay 借助于三方网络插件,Docker Swarm/k8s 集群来实现overlay(容器跨主机通信)
DockerCompose编排
现实场景中,一个项目往往不止一个容器,例如web应用容器、应用服务容器(如Python、Node.js)数据库容器(MySQL、Redis)消息队列容器(RabbitMQ、Kafka)。
当涉及到多个容器时,如果每次都用docker run去去启动容器,每个服务,不仅效率低,管理还困难,还容器出错。Docker Compose正是为了这一痛点而诞生的,它允许你使用一个 YAML 文件来定义并一键启动整个多容器服务架构。需要注意的是:docker compose 是一种针对于容器小型环境所使用的编排工具。更多用于开发和测试环境的多容器管理,而在生产环境下,Docker 推荐使用 Swarm 或Kubernetes 来进行容器编排。
版本区分
docker compose 分为两个版本 V1和V2,早期V1版本独立安装,命令为:docker-compose。现在V2版本默认采用插件安装的,命令为:docker compose。同样,V2版本也可以采用手工独立安装(docker-compose),以下是独立二进制方式部署包地址:
https://github.com/docker/compose/tags
具体部署方法如下:
第一步:下载并将二进制文件更名
[root@docker~]# mv docker-compose-linux-x86_64 /usr/bin/docker-compose
第二步:授权
[root@docker~]# chmod +x /usr/bin/docker-compose
第三步:单独测试
[root@docker~]# docker-compose
也可是使用默认插件安装的命令,该工具是在安装Docker-ce的时候自动安装的。
[root@docker~]# docker compose
语法规则
Compose 文件是一个 YAML 格式的文件,默认名为 docker-compose.yml。其核心结构如下:
services:
服务名称:
image: 镜像名称
build: 构建路径或规则
container_name: 容器名
ports: ["主机端口:容器端口"]
volumes: ["主机目录:容器目录"]
environment:
- VAR_NAME=value
depends_on:
- 另一个服务名称
restart: always|on-failure|unless-stopped
networks:
自定义网络名称:
volumes:
自定义数据卷名称:
也可参考官方文档Docker Compose | Docker Docs
案例操作
启动容器
Docker compose up -d(-d 后台启动)
停止并删除容器
Docker compose down
停止容器
Docker compose stop
如果文件不是标准名称,例如aaa.yaml,在执行的时候需要使用参数-f执行
[root@docker ~]# ls
aaa.yaml
[root@docker ~]# docker compose up -d
no configuration file provided: not found
没找到标准名称叫 docker-compose.yaml的文件
[root@docker ~]# docker compose -f aaa.yaml up -d
Dockerfile自定义镜像
From scratch从零开的的镜像
镜像分层(面试考点)
在使用 Docker 的过程中,我们通常从 镜像(Image) 启动容器。虽然可以使用官方或第三方镜像,但实际开发中,往往需要对镜像进行定制:
安装特定软件包
拷贝自己的应用代码
配置环境变量、默认命令等
镜像一旦被创建,这个镜像(以及被封装的部分)是无法被修改的,因为镜像是分层的。如果想要去修改添加,一定是在原有的镜像基础之上进行的构建。而且,不管镜像多少层,镜像层永久只是只读层。创建容器无非是在镜像只读层的最上方,创建了一层容器读写层。
通过联合文件系统,将镜像只读层和容器读写层一并挂载到当前文件系统中,最终给用户看到的就是一个文件系统。里面包含了所有的镜像层的所有内容。
这种文件系统技术叫UnionFS联合文件系统:
- aufs:容器读写层修改数据,它会一层一层去查找镜像只读层,如果层数嵌套太多,那么寻址速度就会很慢
- Overlayfs(overlay2):容器读写层修改数据,因为底层的每一个上层都会有下一层的硬链接,所以容器读写层看到的所有数据,都可以在最上层的镜像只读层找到。
- Devicemapper:红帽找docker联合并发的一个联合文件系统,性能不好。
常用指令
FROM:指定基础镜像(必须是第一条)
LABEL:添加元数据,如作者信息、备注信息
RUN :执行命令,通常用于安装软件
COPY:复制文件或目录到镜像中
ADD :类似 COPY,但支持解压、URL
WORKDIR:设置工作目录
ENV:设置环境变量
EXPOSE:声明容器运行时监听的端口
VOLUME:声明挂载点,用于数据持久化
CMD :容器启动时默认执行命令(可被替代)
ENTRYPOINT:设置固定入口点(不易被替代)
例子:
[root@docker01 ~]# cat dockerfile
FROM centos:7.9
LABEL author="jinglang"
RUN mkdir /etc/yum.repos.d/bak
RUN mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bak
RUN echo "[online]" > /etc/yum.repos.d/online.repo
RUN echo "name=onlinerepo" >> /etc/yum.repos.d/online.repo
RUN echo "baseurl=https://mirrors.aliyun.com/centos-vault/7.9.2009/os/x86_64/" >> /etc/yum.repos.d/online.repo
RUN echo "gpgcheck=0" >> /etc/yum.repos.d/online.repo
RUN yum clean all
RUN yum repolist all
RUN yum install -y vim net-tools bash-completion
[root@docker01 ~]# docker build -t centos:yum_vs1 -f dockerfile .
命令总结
关于镜像操作
docker images/docker list #查看所有镜像
Doker pull 镜像地址 #拉取镜像
Docker rmi -f 名称 #删除镜像
docker rmi -f $(docker images -qa) #强制删除所有镜像
Docker save 多个镜像名称 -o xxx.tar #镜像的保存
Docker load -i xxx.tar #镜像的载入,可以将导出来的这个文件,拷贝至其他节点,在其他节点载入
关于容器操作
Docker tag 原标签 新标签 #重命名
Docker run -tid --name 容器名称 镜像 #运行进程
-t 指定终端 -i interactive -d 指定容器参数
Docker exec -ti 容器名称(例如os1) /bin/bash #进入容器
如果运行的操作系统是alpine 则为
[root@docker01 ~]# docker exec -ti os1 sh
/ # ls
bin etc lib mnt proc run srv tmp var
dev home media opt root sbin sys usr
Docker rm -f 名称
Docker rm -f $(docker ps -qa) #删除所有容器
Docker stop os1 #容器关闭启动重启
Docker start os1
Docker restart os1
Docker logs db #查询容器日志logs
Docker run -tid --name db -e MYSQL_ROOT_PASSWORD=123456 mysql:8.7 #-e 指定容器环境变量
Docker inspect db |grep -i ipaddr #查询容器详细信息
Docker run -tid --name db -e YSQL_ROOT_PASSWORD=123456 -p 33306:3306 mysql:8 #端口映射
Docker commit os1 alpine:new #将容器提交成镜像
Docker export -o alpine.tar os1 #将容器导出
Docker import
更多推荐

所有评论(0)