Docker入门学习
Docker学习笔记
1.快速入门
准备:linux服务器or虚拟机,OS--Centos7。
安装Docker - 飞书云文档 (feishu.cn) 或者
Linux安装Docker完整教程-腾讯云开发者社区-腾讯云 (tencent.com)
有时候,Docker 官方仓库可能暂时不可用,可以使用镜像源来代替。例如:
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
1.1部署MySQL
使用docker安装MySQL:
docker run -d \ --name mysql01 \ -p 3306:3306 \ -e TZ=Asia/Shanghai \ -e MYSQL_ROOT_PASSWORD=123456 \ mysql:8.0.20
- 镜像和容器
当我们利用Docker安装应用时,Docker会自动搜索并下载应用镜像(image)。镜像不仅包含应用本身,还包含应用运行所需要的环境、配置、系统函数库。Docker会在运行镜像时创建一个隔离环境,称为容器(container)。
镜像仓库:存储和管理镜像的平台,Docker官方维护了一个公共仓库:hub.docker.com
1.2命令解读
docker run -d \ --name mysql01 \ -p 3306:3306 \ -e TZ=Asia/Shanghai \ -e MYSQL_ROOT_PASSWORD=123456 \ mysql:8.0.20
命令 | 描述 |
---|---|
docker run | 创建一个新的容器并运行 |
-d | 让容器后台运行 |
\ | shell命令换行 |
--name [容器名称] | 设置启动容器的名称,必须唯一 |
-p [宿主机端口]:[容器端口] | 设置端口映射,将容器的端口映射到主机的端口 |
-e KEY=VALUE | environment,设置环境变量 |
-e MYSQL_ROOT_PASSWORD=[密码] 设置root用户的密码 |
|
-e TZ=Asia/Shanghai 设置时区 |
|
[repository]:[tag] | 指定运行的镜像的名字,repository就是镜像名,tag是镜像版本,如mysql:8.0.20 。不指定tag则默认为latest,最新版本的镜像 |
2.Docker基础
2.1常见命令
Docker最常见的命令就是操作镜像、容器的命令,详见官方文档:Docker Docs
例子:查看dockerHub,拉取nginx镜像,创建并运行Nginx容器
- 在DockerHub中搜索Nginx镜像,查看镜像的名称
- 拉取Nginx镜像
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker pull nginx Using default tag: latest latest: Pulling from library/nginx a2abf6c4d29d: Pull complete a9edb18cadd1: Pull complete 589b7251471a: Pull complete 186b1aaa4aa6: Pull complete b4df32aa5a72: Pull complete a0bcbecc962e: Pull complete Digest: sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31 Status: Downloaded newer image for nginx:latest docker.io/library/nginx:latest
- 查看本地镜像列表
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest d2c94e258dcb 8 months ago 13.3kB nginx latest 605c77e624dd 2 years ago 141MB mysql 8.0.20 be0dbf01a0f3 3 years ago 541MB
如果要保存下载的镜像,可以使用docker save
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker save --help Usage: docker save [OPTIONS] IMAGE [IMAGE...] Save one or more images to a tar archive (streamed to STDOUT by default) Aliases: docker image save, docker save Options: -o, --output string Write to a file, instead of STDOUT [root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker save -o nginx.tar nginx:latest [root@iZ7xvgwzig5m0o0rnf19bkZ ~]# ll 总用量 142488 -rw------- 1 root root 145902080 1月 20 21:30 nginx.tar
如果docker中没有镜像或者删除了,可以使用docker load 重新加载镜像
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker load -i nginx.tar 2edcec3590a4: Loading layer 83.86MB/83.86MB e379e8aedd4d: Loading layer 62MB/62MB b8d6e692a25e: Loading layer 3.072kB/3.072kB f1db227348d0: Loading layer 4.096kB/4.096kB 32ce5f6a5106: Loading layer 3.584kB/3.584kB d874fd2bc83b: Loading layer 7.168kB/7.168kB Loaded image: nginx:latest
- 创建并运行Nginx容器
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker run -d --name nginx01 -p 80:80 nginx bb29e54fbd8362a84a8eb7a1ab594310b9f3d518d5e9d841977fec512739a45c
- 查看容器
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES bb29e54fbd83 nginx "/docker-entrypoint.…" 50 seconds ago Up 49 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp nginx01 da18e9eda14c mysql:8.0.20 "docker-entrypoint.s…" About an hour ago Up About an hour 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp mysql01
docker ps 命令是查看运行中的容器,如果要查看所有容器,需要添加参数 docker ps -a
- 停止容器
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker stop nginx01 nginx01
- 再次启动容器
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker start nginx01 nginx01
持续查看容器日志:docker logs -f [容器名称]
- 进入Nginx容器
docker exec -it [容器名称] [命令]
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker exec -it nginx01 bash root@bb29e54fbd83:/#
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker exec --help Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...] Execute a command in a running container Aliases: docker container exec, docker exec Options: -d, --detach Detached mode: run command in the background --detach-keys string Override the key sequence for detaching a container -e, --env list Set environment variables --env-file list Read in a file of environment variables -i, --interactive Keep STDIN open even if not attached --privileged Give extended privileges to the command -t, --tty Allocate a pseudo-TTY -u, --user string Username or UID (format: "<name|uid>[:<group|gid>]") -w, --workdir string Working directory inside the container
退出用exit
- 删除容器
删除容器前需要停止容器,否则报错
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker rm nginx01 Error response from daemon: cannot remove container "/nginx01": container is running: stop the container before removing or force remove [root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker stop nginx01 nginx01 [root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker rm nginx01 nginx01
- 命令别名
如果觉得docker的命令太长,可以到 ~/.bashrc 文件中添加命令的别名,简化命令
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# vim ~/.bashrc

保存文件后,使用 source ~/.bashrc 使其生效
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# source ~/.bashrc [root@iZ7xvgwzig5m0o0rnf19bkZ ~]# dis REPOSITORY TAG IMAGE ID CREATED SIZE hello-world latest d2c94e258dcb 8 months ago 13.3kB nginx latest 605c77e624dd 2 years ago 141MB mysql 8.0.20 be0dbf01a0f3 3 years ago 541MB
2.2数据卷
容器是隔离环境,容器内程序的文件、配置、运行时产生的容器都在容器内部,要读写容器内的文件非常不方便。
- 如果要升级MySQL版本,需要销毁旧容器,那么数据岂不是跟着被销毁了?
- MySQL、Nginx容器运行后,如果我要修改其中的某些配置该怎么办?
- 想要让Nginx代理我的静态资源怎么办?
因此,容器提供程序的运行环境,但是程序运行产生的数据、程序运行依赖的配置都应该与容器解耦。
2.2.1什么是数据卷?
数据卷(volume)是一个虚拟目录,是容器内目录与宿主机目录之间映射的桥梁。方便我们操作容器内文件,或者方便迁移容器产生的数据。
比如一个nginx容器中,有两个文件 /etc/nginx/conf
和 usr/share/nginx/html
,但在容器内修改非常麻烦。有了数据卷,我们就可以将数据卷和容器内的目录进行挂载。
步骤如下:
-
首先使用docker命令创建两个数据卷 html 和 conf 。
docker 会自动帮我们在宿主机文件系统中创建两个真实的目录
/var/lib/docker/volumes/html/_data
和/var/lib/docker/volumes/conf/_data
。数据卷html会映射到真实目录下的.../html/_data
,conf 则映射到真实目录下的.../conf/_data
。每一个数据卷都和宿主机上的一个目录进行一一对应。 -
创建数据卷后,让容器目录跟数据卷做挂载。即将容器的目录和数据卷进行关联,这样一来容器的conf目录指向了conf数据卷,conf 数据卷又指向了宿主文件系统的 .../conf/_data 目录,容器的目录就间接地和宿主机的目录产生了关联。一旦关联之后,docker就会自动进行容器内目录和宿主机目录之间的双向绑定和双向映射。
需要注意,数据卷的挂载只能在创建容器的时候进行。如果容器已经创建了是没有办法再去做挂载的。
-
如何挂载数据卷?
-
在创建容器时,利用
-v 数据卷名:容器内目录
完成挂载 -
容器创建时,如果挂载的数据卷不存在,docker将会自动创建
-
-
数据卷的常见命令
命令 释义 docker volume create 创建数据卷 docker volume ls 查看数据卷 docker volume rm 删除指定数据卷 docker volume inspect 查看数据卷详情 docker volume prune 删除所有未使用的数据卷
案例1-利用Nginx容器部署静态资源
需求:
- 创建Nginx容器,修改nginx容器内的html目录下的index.html文件,查看变化
- 将静态资源部署到nginx的html目录
[root@iZ7xvgwzig5m0o0rnf19bkZ _data]# docker run -d --name nginx02 -p 80:80 -v html:/usr/share/nginx/html nginx #创建容器nginx02,并挂载 5d4b9dcde08b22f40769f6b1cb8e1133ec6a982f695952a168b6cd6d47d311fe [root@iZ7xvgwzig5m0o0rnf19bkZ _data]# docker ps #查看运行的容器 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5d4b9dcde08b nginx "/docker-entrypoint.…" 4 seconds ago Up 4 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp nginx02 da18e9eda14c mysql:8.0.20 "docker-entrypoint.s…" 2 days ago Up 8 hours 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp mysql01 [root@iZ7xvgwzig5m0o0rnf19bkZ _data]# docker volume ls #查看数据卷 DRIVER VOLUME NAME local c2699d6d6375a6100df53cb01bc3c8db94316d05c120cf7f93dba0dc334b8f17 local html [root@iZ7xvgwzig5m0o0rnf19bkZ _data]# docker volume inspect html #查看数据卷详情 [ { "CreatedAt": "2024-01-22T22:12:39+08:00", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/html/_data", "Name": "html", "Options": null, "Scope": "local" } ] [root@iZ7xvgwzig5m0o0rnf19bkZ _data]# cd /var/lib/docker/volumes/html/_data/ [root@iZ7xvgwzig5m0o0rnf19bkZ _data]# ls #容器目录的文件映射到此目录下 50x.html index.html
在映射的宿主文件系统目录中修改,可以改变容器目录的文件。同样的修改容器文件,也可以影响宿主目录文件。实现了宿主机目录与容器内目录的双向绑定。
- 匿名数据卷
使用命令 docker inspect [容器名称]
查看MySQL容器详细信息
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker inspect mysql01 [ { ... "Mounts": [ { "Type": "volume", "Name": "c2699d6d6375a6100df53cb01bc3c8db94316d05c120cf7f93dba0dc334b8f17", "Source": "/var/lib/docker/volumes/c2699d6d6375a6100df53cb01bc3c8db94316d05c120cf7f93dba0dc334b8f17/_data", "Destination": "/var/lib/mysql", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], ... "Config": { ... "Volumes": { "/var/lib/mysql": {} }, ... } } } ]
Volumes 部分:可以发现这个容器声明了一个本地目录,需要挂载数据卷,但是数据卷未定义。这就是匿名卷
Mounts 部分:可以发现其中有几个关键属性
- Name:数据卷名称。由于定义的容器未设置数据卷名,这里的就是匿名卷自动生成的名字,一串hash值
- Source:宿主机目录
- Destination:容器内的目录
上述配置将容器内的 /var/lib/mysql
目录,与数据卷 c2699d6d6375a6100df53cb01bc3c8db94316d05c120cf7f93dba0dc334b8f17
挂载。于是在宿主机中就有了 /var/lib/docker/volumes/c2699d6d6375a6100df53cb01bc3c8db94316d05c120cf7f93dba0dc334b8f17/_data
这个目录,即匿名数据卷对应的目录,其使用方式与普通数据卷没有区别。
每一个不同的镜像,将来创建容器后内部有哪些目录可以挂载,可以参考DockerHub对应的页面
2.2.2挂载本地目录或文件(推荐)
可以发现数据卷的目录结构比较深,如果直接去操作不太方便,在很多情况下我们会直接将容器目录和宿主机指定的目录挂载。
挂载语法和数据卷类似:在执行 docker run
命令时,使用 -v [本地目录]:[容器内目录]
可以完成本地目录挂载
#挂载本地目录 -v [本地目录]:[容器内目录] #挂载本地文件 -v [本地文件]:[容器内文件]
注意:本地目录或文件必须以 /
或 ./
开头,如果直接以名字开头会被识别为数据卷名而非本地目录名。
-v mysql:/var/lib/mysql # 会被识别为一个数据卷叫mysql,运行时会自动创建这个数据卷 -v ./mysql:/var/lib/mysql # 会被识别为当前目录下的mysql目录,运行时如果不存在会创建目录
案例2-mysql容器的数据挂载
需求:
- 查看mysql容器,判断是否有数据卷挂载
- 基于宿主机目录实现MySQL数据目录、配置文件、初始化脚本的挂载(查阅官方镜像文档 https://hub.docker.com/)
查阅官方镜像文档知道mysql容器的文件位置分别为:配置文件目录:/etc/mysql/conf.d
,初始化脚本目录:/docker-entrypoint-initdb.d
,数据目录:/var/lib/mysql
。
挂载 /root/mysql/data
到容器内的 /var/lib/mysql
目录
挂载 /root/mysql/init
到容器内的 /docker-entrypoint-initdb.d
目录
挂载 /root/mysql/conf
到容器内的 /etc/mysql/conf.d
目录
#首先创建 init,data,conf目录,然后将准备好的conf,init文件放到对应目录中 [root@iZ7xvgwzig5m0o0rnf19bkZ ~]# tree /root /root └── mysql ├── conf │ └── hm.cnf ├── data └── init └── hmall.sql 4 directories, 2 files #然后创建容器,挂载到本地目录 [root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker run -d \ > --name mysql01 \ > -p 3306:3306 \ > -e TZ=Asia/Shanghai \ > -e MYSQL_ROOT_PASSWORD=123456 \ > -v /root/mysql/data:/var/lib/mysql \ > -v /root/mysql/init:/docker-entrypoint-initdb.d \ > -v /root/mysql/conf:/etc/mysql/conf.d \ > mysql:8.0.20 4f764809252683e4116fa35a24133039b8d82b39e975edf228adc5c0e681954c #查看 /root/mysql/下的目录,可以看到很多文件,说明挂载成功了 [root@iZ7xvgwzig5m0o0rnf19bkZ ~]# tree /root/mysql
本地宿主机目录挂载到容器中,可以方便自定义目录,并且当容器删除后,数据仍可以持久化保存。
比如这里如果将mysql容器删除,只要再次运行创建mysql容器时将之前的本地目录挂载,之前的所有数据依然可以恢复。
2.3自定义镜像
2.3.1镜像的结构
镜像之所以能让我们快速跨操作系统部署应用而忽略其运行环境、配置,就是因为镜像中包含了程序运行需要的系统函数库、环境、配置、依赖。
因此,自定义镜像本质就是依次准备好程序运行的基础环境、依赖、应用本身、运行配置等文件,并且打包而成。
如上,构建一个Java镜像的步骤和部署一个Java应用的步骤类似。而构建镜像的每一步其实都是在生产一些文件(系统运行环境、函数库、配置这些最终都是磁盘文件),所以镜像就是一堆文件的集合。
但是镜像文件不是随意堆放的,而是按照操作的步骤分层叠加而成,每一层形成的文件都会单独打包并标记一个唯一id,称为Layer(层)。照此理解,如果构建镜像时需要用到的其他层别人已经制作过,就可以直接拷贝使用这些层,而不用重复制作。
比如第一步中需要用到的Linux运行环境,因为通用性很强,所以docker官方已经制作了这样的只包含Linux运行环境的镜像。在制作Java镜像时,就无需重复制作,直接使用Docker官方提供的Centos或Ubuntu镜像作为基础镜像(BaseImage)。然后再搭建其他层即可,这样逐层搭建,最终的整个Java项目的镜像如下所示:
2.3.2Dockerfile
Dockerfile就是一个文本文件,其中包含一个个的指令(Instruction),用指令来说明要执行什么操作来构建镜像。将来Docker可以根据Dockerfile帮我们构建镜像。常见指令如下:
更新详细语法说明,请参考官网文档: https://docs.docker.com/engine/reference/builder
指令 | 说明 | 示例 |
---|---|---|
FROM | 指定基础镜像 | FROM centos:6 |
ENV | 设置环境变量,可在后面指令使用 | ENV key value |
COPY | 拷贝本地文件到镜像的指定目录 | COPY ./xx.jar /tmp/app.jar |
RUN | 执行Linux的shell命令,一般是安装过程的命令 | RUN yum install gcc |
EXPOSE | 指定容器运行时监听的端口,是给镜像使用者看的 | EXPOSE 8080 |
ENTRYPOINT | 镜像中应用的启动命令,容器运行时调用 | ENTRYPOINT java -jar xx.jar |
2.3.3构建镜像
我们可以基于Ubuntu基础镜像,利用dockerfile描述镜像结构,也可以直接基于JDK为基础镜像,省略前面的步骤:
写好Dockerfile后可以使用以下命令来构建镜像:
docker build -t [镜像名] [Dockerfile所在路径]
- 例子
dockerfile:
# 基础镜像 FROM openjdk:11.0-jre-buster # 设定时区 ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone # 拷贝jar包 COPY docker-demo.jar /app.jar # 入口 ENTRYPOINT ["java", "-jar", "/app.jar"]
将准备的dockerfile和要运行的jar包放到指定目录,我这里是 /root/demo下
[root@iZ7xvgwzig5m0o0rnf19bkZ demo]# ls /root/demo docker-demo.jar Dockerfile
第一步:下载jar包,然后制作成基础镜像
[root@iZ7xvgwzig5m0o0rnf19bkZ demo]# docker load -i jdk.tar 2c7e7ab2260a: Loading layer 119.3MB/119.3MB 9ad2165feb02: Loading layer 17.18MB/17.18MB 92903c3857f8: Loading layer 17.87MB/17.87MB 1736ab871b32: Loading layer 12.18MB/12.18MB 6f8e4cb95a88: Loading layer 3.584kB/3.584kB 41080a0c646f: Loading layer 141.8MB/141.8MB Loaded image: openjdk:11.0-jre-buster [root@iZ7xvgwzig5m0o0rnf19bkZ demo]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE openjdk 11.0-jre-buster 57925f2e4cff 2 years ago 301MB
第二步:构建镜像
[root@iZ7xvgwzig5m0o0rnf19bkZ demo]# docker build -t mydockerimage . [+] Building 1.6s (8/8) FINISHED docker:default => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 299B 0.0s => [internal] load metadata for docker.io/library/openjdk:11.0-jre-buster 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [1/3] FROM docker.io/library/openjdk:11.0-jre-buster 0.3s => [internal] load build context 0.3s => => transferring context: 17.70MB 0.3s => [2/3] RUN ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo Asia/Shanghai 0.8s => [3/3] COPY docker-demo.jar /app.jar 0.2s => exporting to image 0.1s => => exporting layers 0.1s => => writing image sha256:1b3d36d47dc40e5b7b5e6685d4797b86867ee8cb7876e84a4cf697428123a8e4 0.0s => => naming to docker.io/library/mydockerimage 0.0s
这样自定义镜像就成功了。
#我们查看docker镜像仓库,自定义构建的镜像已经存在了 [root@iZ7xvgwzig5m0o0rnf19bkZ demo]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE mydockerimage latest 1b3d36d47dc4 About a minute ago 319MB openjdk 11.0-jre-buster 57925f2e4cff 2 years ago 301MB #创建运行我们自定义的容器 [root@iZ7xvgwzig5m0o0rnf19bkZ demo]# docker run -d --name test01 -p 8080:8080 mydockerimage 8093e17b7659a8d9a6338d193dbce8ed3e52bad24bd0dc17454e914a9fad2a85 [root@iZ7xvgwzig5m0o0rnf19bkZ demo]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8093e17b7659 mydockerimage "java -jar /app.jar" 9 seconds ago Up 8 seconds 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp test01
也可以使用 docker logs -f [容器名]
查看日志。
2.4网络
默认情况下,所有容器都是以bridge方式连接到docker的一个虚拟网桥上:
但容器的网络IP其实是一个虚拟的IP,其值不与某一个固定的的容器绑定,这意味这如果我们重启了某个容器,docker给这个容器分配的IP就有可能变化,对于我们在开发中写死的IP来说,就意味着容器重启后可能会连接不上。
因此,我们必须借助docker的网络功能来解决这个问题:
加入自定义网络的容器才可以通过容器名相互访问,不需要对方的IP地址,从而解决了容器IP变化带来的问题。
Docker的网络操作命令如下:
命令 | 说明 | 文档地址 |
---|---|---|
docker network create |
创建一个网络 | docker network create |
docker network ls |
查看所有网络 | docs.docker.com |
docker network rm |
删除指定网络 | docs.docker.com |
docker network prune |
清除未使用的网络 | docs.docker.com |
docker network connect |
使指定容器连接加入某网络 | docs.docker.com |
docker network disconnect |
使指定容器连接离开某网络 | docker network disconnect |
docker network inspect |
查看网络详细信息 | docker network inspect |
- 例子
#创建网络 [root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker network create mynet bb39d29512dcf79b8da15314ccfc9d80a72646b09a0b191baa19f8e7fe0e0e88 #查看所有网络 [root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker network ls NETWORK ID NAME DRIVER SCOPE 46fcecfd0e3b bridge bridge local 9c77bd6498c1 host host local bb39d29512dc mynet bridge local e6f0fc103f47 none null local #将mysql01容器连接加入到mynet网络中 [root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker network connect mynet mysql01 #或者指定别名为db,默认每一个容器都有一个别名,即它本身的容器名 #docker network connect hmall mysql --alias db
使用 docker inspect mysql01
可以看到该容器已经加入了新的网络中:

- 也可以在容器创建的时候就可以创建一个网络,并且让容器加入该网络:
docker run -d --name [容器名] -p [主机端口]:[容器端口] --network [网络名] [镜像名]
如:
docker run -d --name test01 -p 8080:8080 --network mynet01 mydockerimage
使用 docker inspect test01
可以发现该容器只有指定的网桥:

进入test01容器内部,使用ping [容器名]
的方式,可以直接连接同一指定网络下的mysql01容器:
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker exec -it test01 bash root@a7c3a0c6041c:/# ping mysql01 PING mysql01 (172.18.0.2) 56(84) bytes of data. 64 bytes from mysql01.mynet (172.18.0.2): icmp_seq=1 ttl=64 time=0.054 ms 64 bytes from mysql01.mynet (172.18.0.2): icmp_seq=2 ttl=64 time=0.060 ms 64 bytes from mysql01.mynet (172.18.0.2): icmp_seq=3 ttl=64 time=0.072 ms ^C --- mysql01 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 2ms rtt min/avg/max/mdev = 0.054/0.062/0.072/0.007 ms
总结:
- 在自定义网络中,可以给容器起多个别名,默认的别名是容器名本身
- 在同一个自定义网络中的容器,可以通过别名互相访问
3.项目部署
3.1手动部署
演示利用docker部署前后端项目
3.1.1部署后端项目
(1)将后端项目打包成jar包,编写好dockerfile

# 基础镜像 FROM openjdk:11.0-jre-buster # 设定时区 ENV TZ=Asia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone # 拷贝jar包 COPY test-service.jar /app.jar # 入口 ENTRYPOINT ["java", "-jar", "/app.jar"]
在项目中,通过访问数据库容器的名称来访问数据库:
(2)将jar包和dockerfile复制到服务器中:
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# ls Dockerfile test-service.jar
(3)构建项目镜像
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker build -t projectimage . [+] Building 3.3s (8/8) FINISHED docker:default => [internal] load build definition from Dockerfile 0.1s => => transferring dockerfile: 300B 0.0s => [internal] load metadata for docker.io/library/openjdk:11.0-jre-buster 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [1/3] FROM docker.io/library/openjdk:11.0-jre-buster 0.0s => [internal] load build context 1.3s => => transferring context: 68.24MB 1.2s => CACHED [2/3] RUN ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo Asia/S 0.0s => [3/3] COPY test-service.jar /app.jar 1.3s => exporting to image 0.4s => => exporting layers 0.4s => => writing image sha256:b37378571ae8f8ba3d81ff730628655e4d685d23a304e1c603e7e9a8831f8e97 0.0s => => naming to docker.io/library/projectimage 0.0s
(4)创建镜像对应的容器并启动
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker run -d --name testproject -p 8080:8080 --network mynet projectimage 16d873208430edd13e7bb52a9ac5cd64d8a06a399e07f8418342bd8898b9a54d
之前已经在Docker中部署过mysql01容器,当项目容器和数据库容器mysql01在同一网桥中,便可以自行连接到数据库中。
测试访问接口:

- 总结:
- 项目打jar包,上传到服务器
- 利用dockerfile,构建项目的镜像
- 用docker run命令创建运行容器
3.1.2部署前端项目
创建一个新的nginx容器,将自定义的nginx.conf、html目录和容器挂载

nginx.conf:
worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/json; sendfile on; keepalive_timeout 65; server { listen 18080; # 指定前端项目所在的位置 location / { root /usr/share/nginx/html/hmall-portal; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } location /api { rewrite /api/(.*) /$1 break; #testproject为之前部署的后端项目容器名称 proxy_pass http://testproject:8080; } } server { listen 18081; # 指定前端项目所在的位置 location / { root /usr/share/nginx/html/hmall-admin; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } location /api { rewrite /api/(.*) /$1 break; #testproject为之前部署的后端项目容器名称 proxy_pass http://testproject:8080; } } }
(1)将文件上传到服务器中
[root@iZ7xvgwzig5m0o0rnf19bkZ nginx]# ls html nginx.conf [root@iZ7xvgwzig5m0o0rnf19bkZ nginx]# pwd /root/nginx
(2)创建nginx容器,并将上述两个文件挂载到nginx容器中
[root@iZ7xvgwzig5m0o0rnf19bkZ nginx]# docker run -d \ > --name nginx01 \ > -p 18080:18080 \ > -p 18081:18081 \ > -v /root/nginx/html:/usr/share/nginx/html \ > -v /root/nginx/nginx.conf:/etc/nginx/nginx.conf \ > --network mynet \ > nginx 6dc5fa9fa1925fd7869fd9bcfad08ac1f7b891e61f197cd1451d3539a284d0ed
mynet是之前创建的网桥
测试访问项目:

总结:
- 准备静态资源html目录和nginx.conf
- 创建容器,进行挂载
需要注意的是,nginx和Java后端项目,后端和数据之间都是使用容器名称来访问的,并且这三个容器都要在同一个网络中
3.2Docker Compose
DockerCompose通过一个单独的docke-compose.yml模板文件(YAML格式)来定义一组相关联的应用容器,帮助我们实现多个相互关联的Docker容器的快速部署。
3.2.1基本语法
docker-compose.yml文件的基本语法可以参考官方文档:
Compose file version 3 reference | Docker Docs
3.2.2基础命令
docker compose的基本语法如下:
docker compose [OPTIONS] [COMMAND]
其中,OPTIONS和COMMAND都是可选参数,比较常见的有:
- 使用DockerCompose演示之前的项目部署
DockerCompose文件:
version: "3.8" services: mysql: #服务名称 image: mysql:8.0.20 #镜像,若本地没有,Compose将尝试从互联网拉取这个镜像 container_name: mysql01 #容器名 ports: - "3306:3306" #端口映射 environment: #环境参数配置 TZ: Asia/Shanghai MYSQL_ROOT_PASSWORD: 123456 volumes: #自定义挂载本地目录 - "./mysql/conf:/etc/mysql/conf.d" - "./mysql/data:/var/lib/mysql" - "./mysql/init:/docker-entrypoint-initdb.d" networks: #网络设置 - my-net javaproject: build: #每个服务都必须通过image指令指定镜像,或build指令(需要 Dockerfile)等来自动构建生成镜像。 context: . dockerfile: Dockerfile container_name: testproject ports: - "8080:8080" networks: #加入哪个网络中 - my-net depends_on: #依赖于哪个服务 - mysql nginx: image: nginx container_name: nginx01 ports: - "18080:18080" - "18081:18081" volumes: - "./nginx/nginx.conf:/etc/nginx/nginx.conf" - "./nginx/html:/usr/share/nginx/html" depends_on: - javaproject networks: - my-net networks: my-net: #这里是网络的标识 name: mynet #网络的名字 ex
(1)将之前的容器、自定义的镜像、网络全部删除
[root@iZ7xvgwzig5m0o0rnf19bkZ demo]# docker rm -f nginx01 testproject mysql01 nginx01 testproject mysql01 [root@iZ7xvgwzig5m0o0rnf19bkZ demo]# docker rmi projectimage mydockerimage Untagged: projectimage:latest Deleted: sha256:b37378571ae8f8ba3d81ff730628655e4d685d23a304e1c603e7e9a8831f8e97 [root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker network rm mynet mynet
(2)将DockerCompose文件上传到对应的文件路径下,并使用DockerCompose命令一键启动部署项目
注意:dockercompose文件中需要用到的目录和文件等,需要事先创建和放到对应的路径中
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker compose up -d [+] Building 0.1s (8/8) FINISHED docker:default => [javaproject internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 300B 0.0s => [javaproject internal] load metadata for docker.io/library/openjdk:11.0-jre-buster 0.0s => [javaproject internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [javaproject 1/3] FROM docker.io/library/openjdk:11.0-jre-buster 0.0s => [javaproject internal] load build context 0.0s => => transferring context: 40B 0.0s => CACHED [javaproject 2/3] RUN ln -snf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && 0.0s => CACHED [javaproject 3/3] COPY test-service.jar /app.jar 0.0s => [javaproject] exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:6b312ff9212db83ffed789f8680aaf8e088c1ae23de2ba8faa7dcc99bb93e342 0.0s => => naming to docker.io/library/root-javaproject 0.0s [+] Running 3/4 ⠧ Network mynet Created 2.7s ✔ Container mysql01 Started 0.5s ✔ Container testproject Started 1.0s ✔ Container nginx01 Started 2.2s
查看项目下的所有进程:
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker compose ps NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS mysql01 mysql:8.0.20 "docker-entrypoint.s…" mysql About a minute ago Up About a minute 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp nginx01 nginx "/docker-entrypoint.…" nginx About a minute ago Up About a minute 80/tcp, 0.0.0.0:18080-18081->18080-18081/tcp, :::18080-18081->18080-18081/tcp testproject root-javaproject "java -jar /app.jar" javaproject About a minute ago Up About a minute 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp
在浏览器访问项目成功,说明所有服务都成功部署:

使用docker compose的删除命令,整个项目创建的所有服务容器和网络都可以一键删除:
[root@iZ7xvgwzig5m0o0rnf19bkZ ~]# docker compose down [+] Running 4/4 ? Container nginx01 Removed 0.3s ? Container testproject Removed 0.4s ? Container mysql01 Removed 1.9s ? Network mynet Removed 0.2s
DockerCompose的功能远不止如此,它还可以用来做集群的部署。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
2023-02-10 day06-SpringMVC底层机制简单实现-02