Docker 入门
初识 Docker
概念
虚拟机的出现使得 同一台物理机上实现多个操作系统(OS)运行不同 App 达到目的 成为可能
但是当虚拟机数量越来越多 或者所运行的 App 消耗的资源越来越大时 对物理机会产生极大消耗
为了使得系统性能不被多个虚拟机中的 OS 所消耗,容器技术(Container)应运而生
与虚拟机不同,容器技术依赖容器支持层,创建多个容器,用以运行多个 App
优点是极大地降低了资源消耗,同时形成多个虚拟机的效果,其中最流行的容器技术就是 Docker
Docker 的特点
- 基于 Linux 实现的虚拟技术
- 依据进程隔离实现的
- 体积小、占用资源少
- 启动快
作用
- 用于解决软件开发中的环境配置,作用类似于 Python 的虚拟环境
安装
- MacOS 系统访问 https://docs.docker.com/desktop/install/mac-install/
- Windows 系统访问 https://docs.docker.com/desktop/install/windows-install/
- ubuntu 系统访问 https://docs.docker.com/engine/install/ubuntu/
- centos 系统访问 https://docs.docker.com/engine/install/centos/
- 显示 docker 版本
docker -v
1 | root@ubuntu-server:~# docker -v |
- 显示 docker 详细信息
docker info
1 | root@ubuntu-server:/# docker info |
- 查看 docker 运行状态
systemctl status docker
1 | root@ubuntu-server:~# systemctl status docker |

- 设置 docker 开机自启动
systemctl enable docker
Docker 运行
最初,刚安装好 docker 的机器不存在镜像因此没办法运行
运行docker run hello-world的效果如下,由于设备上还没有拉取任何镜像,因此是从 library 上拉取的
1 | root@ubuntu-server:~# docker run hello-world |
启动容器
docker run [镜像名称],若该镜像不存在 则会默认拉取最新的
1 | root@ubuntu-server:~# docker run nginx |
会启动一个 nginx 服务,并且等待着

查看当前容器
docker ps查看正在运行中的或者创建了的容器docker ps -a查看所有容器
1 | root@ubuntu-server:~# docker ps |
docker inspect [容器ID],查看容器的信息
1 | root@ubuntu-server:~# docker inspect 8e1148f9c025 |

curl http://[IpAddress]:[Ports]访问该 nginx 服务
1 | root@ubuntu-server:~# curl http://172.17.0.2:80 |
这时候 我出现了一个问题,通过 IPAddress 访问不到,但是通过容器内部可以访问到,并且 ping 不通 172.17.0.2,解决方法如下
1 | root@ubuntu-server:/# cd /etc/docker/ |
之后尝试重新创建一个 nginx 容器
1 | root@ubuntu-server:~# docker run nginx |
然后使用curl http://172.17.0.2:80运行一下
1 | root@ubuntu-server:~# docker ps -a |
并且在另一边的 nginx 服务上可以看到访问
1 | root@ubuntu-server:~# docker run nginx |
停止与删除容器
docker stop [容器ID]停止一个容器docker <container> rm [容器ID]/[容器名:Tag]删除一个容器,一个容器必须先停止了 才能被删除docker run --rm [容器名称]创建一个容器,容器停止时自动删除docker container prune删除所有已经停止的容器
1 | root@ubuntu-server:~# docker ps -a |
启动指定 Image 版本容器
docker run [镜像名称]默认表示最新版本的镜像docker run [镜像名称]:[版本号]使用版本号指定的镜像- 查看官方维护的镜像版本号 https://hub.docker.com/

1 | root@ubuntu-server:~# docker run nginx:1.24.0 |
其他的一些操作比如容器的停止与删除等都与之前一致
1 | root@ubuntu-server:~# curl http://172.17.0.2:80 |
创建交互式终端容器
docker run -it <--name=[容器名称]> [镜像名称]<:[版本号]>启动后可在控制台打印输出与获取输入docker run -it <--name=[容器名称]> [镜像名称]<:[版本号]> bash启动后直接进入交互终端exit退出交互式终端
1 | root@ubuntu-server:~# docker run -it --name=nginx_test1 nginx |
1 | root@ubuntu-server:~# docker ps -a |
启动映射端口的容器
如果想要实现通过主机 ip 对 docker 的服务进行访问 需要执行端口映射
docker run -p [主机端口]:[容器端口] [镜像名称]<:[版本号]>
1 | root@ubuntu-server:~# docker run -p 8089:80 nginx |
然后获取主机的 ip 地址
1 | root@ubuntu-server:~# ifconfig |
之后在浏览器通过访问主机 ip 地址+port 端口号 (192.168.7.128:8089),访问刚才启动的 nginx 服务

启动容器时配置环境变量
docker run mysql启动一个 MySQL 容器
1 | root@ubuntu-server:~# docker run mysql |
提示需要执行以下任意一个命令
You need to specify one of the following as an environment variable:
- MYSQL_ROOT_PASSWORD
- MYSQL_ALLOW_EMPTY_PASSWORD
- MYSQL_RANDOM_ROOT_PASSWORD
这时候如果可以实现在启动容器的时候 就配置上环境变量,就可以实现
docker run -e [变量名]=[变量值] [镜像名称]
1 | root@ubuntu-server:~# docker run -e MYSQL_ROOT_PASSWORD=123456 mysql |
服务启动之后可以尝试连接一下
1 | root@ubuntu-server:~# docker ps |
启动容器时配置路径映射
当 docker 中的一个 mysql 服务容器删除之后,之前在这个容器中创建的数据库、表都会消失掉;
那如果可以将主机的某个路径(磁盘卷)映射到容器中,使得数据库、表存储在主机中,就不会因为容器的删除而导致数据的丢失
docker run -v [主机路径]:[容器路径] [镜像名称]创建一个映射路径的容器
先停掉之前的服务,然后创建 第一个 mysql 容器,然后在这个容器里面创建 一个数据库 之后删除掉这个容器
1 | root@ubuntu-server:~# docker run -e MYSQL_ROOT_PASSWORD=123456 -v /opt/mysql:/var/lib/mysql mysql |
紧接着 再次执行 创建映射的 MySQL 容器 查看一下之前所创建的数据库是否存在
1 | root@ubuntu-server:~# docker run -e MYSQL_ROOT_PASSWORD=123456 -v /opt/mysql:/var/lib/mysql mysql |
自定义 docker Image 镜像
之前的操作都是在拉取官方的 image 运行的,若想实现一个自己的 image 需要如何操作
查看已拉取镜像
docker imagesdocker image ls
1 | root@ubuntu-server:~# docker image ls |
拉取镜像
docker pull [镜像名称image_name]<:[版本号Tag]>不指定版本号默认拉取最新版本
1 | root@ubuntu-server:~# docker pull centos |
删除镜像
docker image rm [镜像名称image_name]<:[版本号Tag]>不指定版本号默认删除最新版本docker rmi [镜像名称image_name]<:[版本号Tag]>
1 | root@ubuntu-server:~# docker image rm centos |
编写 Dockerfile
新建一个 Flask 项目并且创建 Dockerfile、app.py、requirements.txt
1 | FROM ubuntu:latest |
1 | flask |
1 | from flask import Flask |
将上述代码打包放到 GitHub:https://github.com/BlockZachary/flaskDockerSample

然后在服务器主机上面操作,先将代码克隆到主机上
1 | root@ubuntu-server:~/pythonProject# git clone https://github.com/BlockZachary/flaskDockerSample.git |
构建自己的 Image
docker build . -t [镜像名称]<:[版本号]>不填写版本号默认是一个 latest .指的是当前目录
1 | root@ubuntu-server:~/pythonProject/flaskDockerSample# docker build . -t myflasksample |
启用自定义 Image 的容器
因为这块用的例子是一个 flask 项目,端口号用的默认是 5000
1 | root@ubuntu-server:~/pythonProject/flaskDockerSample# docker run -p 8080:5000 myflasksample |
1 | root@ubuntu-server:~# docker ps |
使用浏览器也可以正常访问


创建 docker 官方账号、登录
首先在https://hub.docker.com/,注册账号
然后可以在主机中使用 docker login、docker logout进行登录、登出
1 | root@ubuntu-server:~# docker login |
然后再去官网创建一个仓库


可以看到右侧有一段这样的命令:docker push zacharyblock/myflasksample:tagname,
为了实现推送的,必须有一个名称为 zacharyblock/myflasksample的镜像,但是前一步操作,我们只构建了一个名称为myflasksample的镜像,因此我们还需要重新构建一次

使用docker build . -t zacharyblock/myflasksample构建一下 image
1 | root@ubuntu-server:~/pythonProject/flaskDockerSample# docker build . -t zacharyblock/myflasksample |
推送镜像到远程仓库
docker push [镜像名称]<:[版本号]>
1 | root@ubuntu-server:~/pythonProject/flaskDockerSample# docker push zacharyblock/myflasksample |
推送好了之后,官网可以看到

尝试一下拉取,先删除掉已经有的这个 image,然后再拉取
1 | root@ubuntu-server:~# docker images |
Dockerfile 的 CMD 与 ENTRYPOINT
CMD
为了可以使用命令或者参数在启动容器的时候启动一些我们需要的默认程序,可以使用 CMD
- Dockerfile 中的 CMD 指令格式
CMD [shell命令]通过 sh 的形式CMD ["命令","参数1","参数2",...]
- 如果 Dockerfile 中存在多条 CMD 最后一条生效
- 可以通过在启动容器时,添加参数对 CMD 命令进行替换
docker run -it [镜像] [命令] [参数1] [参数2]
这块来一个例子
仍旧是在 ubuntu 主机上面先创建一个项目目录,然后准备 Dockerfile 和 app.py
1 | root@ubuntu-server:~/pythonProject# mkdir cmdDockerSample |
然后对该项目进行镜像构建,构建一个容器后会打印出参数,也可以通过命令参数进行 CMD 替换
1 | root@ubuntu-server:~/pythonProject/cmdDockerSample# docker build . -t cmddockersample |
ENTRYPOINT
用于指定启动容器时候默认运行的程序
- Dockerfile 中的 ENTRYPOINT 指令格式
ENTRYPOINT [shell命令]通过 sh 的形式ENTRYPOINT ["命令","参数1","参数2",...]
- 如果 Dockerfile 中只能定义一个 ENTRYPOINT
- 在启动容器时,不可以对 ENTRYPOINT 命令进行替换
- 可以用 CMD 给 ENTRYPOINT 指定参数
来一个实例看看
先创建一个 entrypointDockerSample 目录,然后还是创建 Dockerfile 和 app.py
1 | root@ubuntu-server:~/pythonProject# mkdir entrypointDockerSample |
通过上面的例子可以看出来,当使用了 entrypoint 的时候 在创建容器的时候命令行增加的参数并没有替换掉原先的参数 而是给原先的参数增加上了
CMD 结合 ENTRYPOINT
通过上面两个例子,如果将 CMD 和 ENTRYPOINT 结合起来使用 可以实现对既定的命令保持不变 对某些参数进行替换的操作
1 | root@ubuntu-server:~/pythonProject# mkdir cmdEntrypointDockerSample |
多容器互联
建立多容器互联网络
docker network ls查看当前所有网络docker network create [网络名称]创建一个新的网络docker network rm [网络名称]移除一个网络
1 | root@ubuntu-server:~# docker network ls |
启动容器并加入互联网络
docker run --network [要加入的网络名称] --network-alias [容器在网络中的别名] [镜像名称]
自己制作一个镜像
1 | FROM ubuntu |
1 | root@ubuntu-server:~/dockerDIYImage/ubuntu_Ping# nano Dockerfile |
首先在一个控制台创建一个容器并起别名
1 | root@ubuntu-server:~# docker run -it --rm --network nw_test --network-alias c1 myos |
然后在另一个控制台创建另一个容器
1 | root@ubuntu-server:~# docker run -it --rm --network nw_test --network-alias c2 myos |
然后分别在两个控制台中 ping 对方容器的别名
1 | root@ubuntu-server:~# docker run -it --rm --network nw_test --network-alias c1 myos |
1 | root@ubuntu-server:~# docker run -it --rm --network nw_test --network-alias c2 myos |
创建一个 MySQL 容器并加入互联网络
1 | root@ubuntu-server:~# docker run -d --rm --network nw_test --network-alias mysql_server -v /opt/mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=wordpressdb mysql |
创建一个 Wordpress 容器并加入互联网络
1 | root@ubuntu-server:~# docker run -d --rm -p 82:80 --network nw_test --network-alias wordpress_server -e WORDPRESS_DB_HOST=mysql_server -e WORDPRESS_DB_NAME=wordpressdb -e WORDPRESS_DB_USER=root -e WORDPRESS_DB_PASSWORD=123456 wordpress |
在浏览器输入主机 ip:82,可以进入 wordpress 页面

有这个问题 去解决一下,需要连接一下对应的 mysql 数据库创建一下这个库
1 | root@ubuntu-server:~# docker inspect 6b07fc530884 | grep "IPAddress" |

现在就可以啦,初步配置一下



用刚才的用户名和密码进行登录,就进入到后台

比如我们修改一下外观

这个时候用自己的服务器主机的 ip+82,可以访问到主页

可以对文章进行编辑


然后可以查看到效果

Compose
用于定义和运行多容器的工具,简化上一节中讲到的多容器互联复杂的命令输入环节
- 通过 YAML 文件的格式定义多容器关系
安装 docker compose
- Mac 和 Windows 下的 docker 默认已经安装了 docker compose
- Linux 下的 ubuntu 安装 docker compose
apt-get install docker-compose

1 | root@ubuntu-server:~# docker-compose --version |
定义 Docker Compose 多容器
创建一个 docker-compose.yaml 文件
1 | version: "3.8" |
1 | root@ubuntu-server:~# ls |
启动与停止 Docker Compose
docker compose up启动docker compose down停止
1 | root@ubuntu-server:~/dockerProject/myWebSite# docker compose up |
启动之后可以直接使用浏览器访问服务器 ip+82,可以直接访问到上一节的服务,因为之前是映射了 mysql 数据到了服务器主机上面的,所以这次只要还是映射了,数据依然存在,当然如果删除掉了数据,就会重新创建

1 | root@ubuntu-server:~/dockerProject/myWebSite# docker compose down |
构建自己的镜像启动多容器
1 | FROM ubuntu |
1 | import sqlalchemy |
1 | version: "3.8" |
1 | mysqlclient==2.1.1 |
由于网络太慢了 修改一下 Dockerfile
1 | FROM ubuntu |
但是这时候还是出了问题,定位到最后是因为没有初始化 mydb 这个数据库
1 | root@ubuntu-server:~/dockerProject/docker_dbmanager# docker compose up --build |
我们不关闭这个,重新开一个终端
1 | root@ubuntu-server:~/dockerProject/docker_dbmanager# docker ps -a |
然后重新执行一次拉起操作
1 | root@ubuntu-server:~/dockerProject/docker_dbmanager# docker compose up --build |

最后可以停掉这个多容器
1 | root@ubuntu-server:~/dockerProject/docker_dbmanager# docker compose down |
Docker Image 相关命令速查
docker search [镜像名称]查找镜像信息docker pull [镜像名称]拉取镜像docker image lsdocker images查看镜像列表docker rmi [镜像名称/镜像ID]删除镜像docker save -o [输出文件名] [镜像名称/镜像ID]将镜像保存为文件,便于传输镜像docker save --output [输出文件名] [镜像名称/镜像ID]docker save [镜像名称/镜像ID] > [输出文件名]docker load -i [镜像文件]将文件加载为镜像 Imagedocker load --input [镜像文件]docker load < [镜像文件]docker build . -t [构建的镜像名称]自定义镜像 默认找当前目录下 Dockerfiledocker build -f [Dockerfile文件名] -t [构建的镜像名称] [Dockerfile所在目录]
Docker Container 相关命令速查
docker run--pull [missing/never/always]- missing 每次运行时候如果没有镜像就拉去 如果有就不拉取 默认也就是 missing 模式
- never 每次运行的时候都不去拉取镜像
- always 每次运行的时候都去拉取一次镜像
-i以交互的方式运行-t输出到控制台-it经常这样用-rm容器停止以后直接删除-v [主机路径]:[容器内部路径]做目录映射的,MySQL 常用避免容器删除后数据清空了-p [主机端口]:[容器端口]端口映射,通过主机的端口来访问容器端口的服务-e(--env) [环境变量]配置环境变量,如 MySQL 的登录名、端口、密码等--env-file [环境变量定义文件]配置环境变量定义文件--network [加入的网络名称] --network-alias [容器在网络中的别名]网络与别名--name [容器名称][镜像名称][命令]容器启动后的命令
docker ps查看本地运行的容器docker ps -a查看本地所有的容器docker stop [容器ID]停止一个正在运行的容器docker start [容器ID]启动一个已经停止了的容器docker restart [容器ID]重启一个容器docker kill [容器ID]docker rm [容器ID]删除容器docker attach [容器ID]重新在控制台显示容器输出的内容 有时候以-d 运行的容器 后续内容不会打印docker history [容器名称]查看执行该容器的历史命令docker exec -d [容器名称/容器ID] [要执行的命令]对某个容器执行一条命令,但看不见后续内容docker exec -it [容器名称/容器ID] [要执行的命令(常用bash进入交互)]docker export -o [导出的容器文件名称] [容器ID]导出容器docker import [要导入的容器文件]导入容器docker cp [源文件] [目标文件]在主机与容器之间复制文件
更新: 2024-02-01 02:30:01
原文: https://www.yuque.com/zacharyblock/cx2om6/oxlyrpyvo0ylgtio