1270 lines
34 KiB
Markdown
1270 lines
34 KiB
Markdown
|
## Docker
|
|||
|
|
|||
|
### docker基础知识
|
|||
|
|
|||
|
#### 镜像和容器
|
|||
|
|
|||
|
Docker中有几个重要的概念:
|
|||
|
|
|||
|
**镜像(Image)**:Docker将应用程序及其所需的依赖、函数库、环境、配置等文件打包在一起,称为镜像,是只读的。
|
|||
|
|
|||
|
**容器(Container)**:镜像中的应用程序运行后形成的进程就是容器,只是Docker会给容器进程做隔离,对外不可见。因此一个镜像可以启动多次,形成多个容器进程。
|
|||
|
|
|||
|
一切应用最终都是代码组成,都是硬盘中的一个个的字节形成的**文件**。只有运行时,才会加载到内存,形成进程。
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Docker为了解决依赖的兼容问题的,采用了两个手段:
|
|||
|
|
|||
|
- 将应用的Libs(函数库)、Deps(依赖)、配置与应用一起打包
|
|||
|
|
|||
|
- 将每个应用放到一个隔离**容器**去运行,避免互相干扰
|
|||
|
|
|||
|
<img src="D:/folder/test/output/af6583c2-265f-46e1-908d-b1b01dd25f97.png" alt="image-20210731142219735" style="zoom: 67%;" />
|
|||
|
|
|||
|
这样打包好的应用包中,既包含应用本身,也保护应用所需要的Libs、Deps,无需在操作系统上安装这些,自然就不存在不同应用之间的兼容问题了。
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#### DockerHub
|
|||
|
|
|||
|
开源应用程序非常多,打包这些应用往往是重复的劳动。为了避免这些重复劳动,人们就会将自己打包的应用镜像,例如Redis、MySQL镜像放到网络上,共享使用,就像GitHub的代码共享一样。
|
|||
|
|
|||
|
- DockerHub:DockerHub是一个官方的Docker镜像的托管平台。这样的平台称为Docker Registry。
|
|||
|
|
|||
|
- 国内也有类似于DockerHub 的公开服务,比如 [网易云镜像服务](https://c.163yun.com/hub)、[阿里云镜像库](https://cr.console.aliyun.com/)等。
|
|||
|
|
|||
|
注意:很多国内的镜像现在也不能用了!需要换源!
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#### Docker架构
|
|||
|
|
|||
|
我们要使用Docker来操作镜像、容器,就必须要安装Docker。
|
|||
|
|
|||
|
Docker是一个CS架构的程序,由两部分组成:
|
|||
|
|
|||
|
- 服务端(server):Docker守护进程,负责处理Docker指令,管理镜像、容器等
|
|||
|
|
|||
|
- 客户端(client):通过命令或RestAPI向Docker服务端发送指令。可以在本地或远程向服务端发送指令。
|
|||
|
|
|||
|
如图:
|
|||
|
|
|||
|

|
|||
|
|
|||
|
|
|||
|
|
|||
|
#### 镜像操作
|
|||
|
|
|||
|

|
|||
|
|
|||
|
1. docker push,将本地镜像上传到远程仓库(例如 Docker Hub)
|
|||
|
|
|||
|
```
|
|||
|
docker login #docker hub登录
|
|||
|
# 假设已有本地镜像 myimage,需要先打上标签:
|
|||
|
docker tag myimage yourusername/myimage:latest
|
|||
|
# 上传镜像到远程仓库:
|
|||
|
docker push yourusername/myimage:latest
|
|||
|
```
|
|||
|
|
|||
|
2. docker pull ,从远程仓库拉取镜像到本地。
|
|||
|
|
|||
|
```
|
|||
|
docker pull yourusername/myimage:latest
|
|||
|
```
|
|||
|
|
|||
|
3. docker save,将本地镜像保存为 tar 文件,方便备份或传输
|
|||
|
|
|||
|
```
|
|||
|
docker save -o myimage.tar yourusername/myimage:latest
|
|||
|
```
|
|||
|
|
|||
|
4. docker load,从 tar 文件中加载镜像到本地 Docker。
|
|||
|
|
|||
|
```
|
|||
|
docker load -i myimage.tar
|
|||
|
```
|
|||
|
|
|||
|
5. docker images ,查看本地镜像
|
|||
|
|
|||
|
```
|
|||
|
docker images
|
|||
|
```
|
|||
|
|
|||
|
6. docker build ,构建镜像 -t后面跟镜像名
|
|||
|
|
|||
|
```
|
|||
|
docker build -t yourusername/myimage:latest .
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#### 容器操作
|
|||
|
|
|||
|

|
|||
|
|
|||
|
1. docker run 创建并运行一个新容器
|
|||
|
|
|||
|
-d:以后台模式运行容器,不会占用当前终端。
|
|||
|
|
|||
|
--name <容器名> :为容器指定一个自定义名称,便于后续管理。
|
|||
|
|
|||
|
-p <宿主机端口>:<容器端口> : 将容器内部的端口映射到宿主机,使外部可以访问容器提供的服务。
|
|||
|
|
|||
|
--restart <策略> :设置容器的重启策略,如 `no`(默认不重启)、`on-failure`(失败时重启)、`always`(总是重启)或 `unless-stopped`。
|
|||
|
|
|||
|
-v <宿主机目录>:<容器目录>` 或 `--volume : 如 -v /host/data:/app/data
|
|||
|
|
|||
|
```
|
|||
|
docker run --name test-container -d test:latest
|
|||
|
```
|
|||
|
|
|||
|
2. docker exec 在正在运行的 test-container 内执行命令
|
|||
|
|
|||
|
-it : 给当前进入的容器创建一个标准输入、输出终端
|
|||
|
|
|||
|
```
|
|||
|
docker exec -it test-container sh
|
|||
|
```
|
|||
|
|
|||
|
3. docker logs ,查看 test-container 的日志输出:
|
|||
|
|
|||
|
```
|
|||
|
docker logs --since 1h test-container #查看最近1h
|
|||
|
```
|
|||
|
|
|||
|
4. docker stop 停止正在运行的 test-container:
|
|||
|
|
|||
|
```
|
|||
|
docker stop test-container
|
|||
|
```
|
|||
|
|
|||
|
5. docker start 启动一个已停止的 test-container:
|
|||
|
|
|||
|
```
|
|||
|
docker start test-container
|
|||
|
```
|
|||
|
|
|||
|
6. docker cp 复制文件(或目录)到容器内部,先cd到文件所在目录
|
|||
|
|
|||
|
```
|
|||
|
docker cp localfile.txt test-container:/target_dir/
|
|||
|
```
|
|||
|
|
|||
|
7. docker stats ,查看docker中运行的所有容器的运行状态(CPU 内存占用)
|
|||
|
|
|||
|
```
|
|||
|
docker stats
|
|||
|
```
|
|||
|
|
|||
|
8. docker container ls,查看运行容器的创建时间、端口映射等
|
|||
|
|
|||
|
```
|
|||
|
docker container ls
|
|||
|
```
|
|||
|
|
|||
|
9. docker ps 查看 Docker 容器的状态,默认情况下,它只显示正在运行的容器
|
|||
|
|
|||
|
```
|
|||
|
docker ps -a #查看所有容器,包括已经停止或启动失败的容器
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#### 数据卷操作
|
|||
|
|
|||
|
**数据卷(volume)**是一个虚拟目录,指向宿主机文件系统中的某个目录。
|
|||
|
|
|||
|

|
|||
|
|
|||
|
一旦完成数据卷挂载,对容器的一切操作都会作用在数据卷对应的宿主机目录了。
|
|||
|
|
|||
|
这样,我们操作宿主机的/var/lib/docker/volumes/html目录,就等于操作容器内的/usr/share/nginx/html目录了
|
|||
|
|
|||
|
有两种挂载方式:
|
|||
|
|
|||
|
**绑定挂载(Bind Mounts)更加推荐!**
|
|||
|
|
|||
|
- **原理**:直接将宿主机上的一个目录或文件挂载到容器内。
|
|||
|
|
|||
|
- **特点**
|
|||
|
|
|||
|
- 数据存储在宿主机上,容器可以直接访问宿主机的文件系统。
|
|||
|
- 适合需要在开发过程中频繁修改代码或数据共享的场景。
|
|||
|
- 依赖宿主机的目录结构,移植性较低。
|
|||
|
|
|||
|
- **示例**:将宿主机的 `/path/on/host` 挂载到容器内的 `/app/data`:
|
|||
|
|
|||
|
```
|
|||
|
docker run -v /path/on/host:/app/data your_image
|
|||
|
```
|
|||
|
|
|||
|
**命名卷(Docker Volumes)**
|
|||
|
|
|||
|
- **原理**:由 Docker 管理的数据卷,存储在 Docker 的默认目录(通常在 `/var/lib/docker/volumes/`),或通过 Docker 卷插件存储到其他位置。
|
|||
|
|
|||
|
- **特点**
|
|||
|
|
|||
|
- Docker 负责管理这些卷,提供更好的隔离和数据持久性。
|
|||
|
- 与宿主机的具体目录结构无关,便于迁移和备份。
|
|||
|
- 常用于生产环境中数据的持久化。
|
|||
|
|
|||
|
- **示例**:创建并挂载名为 `my_volume` 的卷到容器内的 `/app/data`:
|
|||
|
|
|||
|
```
|
|||
|
docker run -v my_volume:/app/data your_image
|
|||
|
```
|
|||
|
|
|||
|
创建命名卷
|
|||
|
|
|||
|
```
|
|||
|
docker volume create my_volume
|
|||
|
```
|
|||
|
|
|||
|
查看命名卷,这将列出所有 Docker 管理的卷。
|
|||
|
|
|||
|
```
|
|||
|
docker volume ls
|
|||
|
```
|
|||
|
|
|||
|
显示该命名卷的详细信息
|
|||
|
|
|||
|
```
|
|||
|
zy123@hcss-ecs-588d:~/zbparse$ sudo docker volume inspect html
|
|||
|
[
|
|||
|
{
|
|||
|
"CreatedAt": "2025-02-25T18:46:10+08:00",
|
|||
|
"Driver": "local",
|
|||
|
"Labels": null,
|
|||
|
"Mountpoint": "/var/lib/docker/volumes/html/_data",
|
|||
|
"Name": "html",
|
|||
|
"Options": null,
|
|||
|
"Scope": "local"
|
|||
|
}
|
|||
|
]
|
|||
|
```
|
|||
|
|
|||
|
Mountpoint是宿主机上的路径,也就是 Docker 存储该数据卷数据的**实际位置**
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#### docker网络
|
|||
|
|
|||
|
Docker 网络的主要作用是实现容器之间的**通信和隔离**,同时也能控制容器与外部主机或网络的连接。通过创建自定义网络,你可以让属于同一网络的容器通过名称互相访问,而不必暴露所有服务到外部网络,这既提升了安全性又简化了容器间的交互。
|
|||
|
|
|||
|
**举例说明**
|
|||
|
|
|||
|
假设你有两个容器,一个运行 MySQL 数据库,另一个运行 Web 应用程序。你希望 Web 应用能够通过数据库容器的别名来访问 MySQL,而不需要硬编码 IP 地址。
|
|||
|
|
|||
|
1.创建自定义网络 ,名为 `app-net`
|
|||
|
|
|||
|
```
|
|||
|
docker network create app-net
|
|||
|
```
|
|||
|
|
|||
|
2.启动 MySQL 容器,并加入 `app-net` 网络,同时为其指定别名 `db`
|
|||
|
|
|||
|
```
|
|||
|
docker run -d --name mysql \
|
|||
|
--network app-net \
|
|||
|
--network-alias db \
|
|||
|
-e MYSQL_ROOT_PASSWORD=my-secret-pw \
|
|||
|
mysql:latest
|
|||
|
```
|
|||
|
|
|||
|
**Docker CLI 命令**(如 `docker ps`、`docker exec`)**需要使用 `container_name` 来操作容器**。
|
|||
|
|
|||
|
但如果 **另一个容器需要访问它,不能直接用 `mysql`容器名,而要用 IP 地址或 `network-alias`**。
|
|||
|
|
|||
|
`--network-alias db`(网络别名),只在特定网络中生效
|
|||
|
|
|||
|
注意:不使用docker-compose就没有服务名,可以通过容器名,**网络别名**实现同网络的容器间通信
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
3.启动 Web 应用容器,加入同一个 `app-net` 网络
|
|||
|
|
|||
|
```
|
|||
|
docker run -d --name webapp \
|
|||
|
--network app-net \
|
|||
|
your_webapp_image:latest
|
|||
|
```
|
|||
|
|
|||
|
4.验证容器间通信,进入 Web 应用容器,尝试通过别名 `db` 连接 MySQL:
|
|||
|
|
|||
|
```
|
|||
|
docker exec -it webapp bash
|
|||
|
# 在 webapp 容器内执行,比如使用 ping 测试网络连通性:
|
|||
|
ping db
|
|||
|
```
|
|||
|
|
|||
|
举个例子,如果你的 Java 应用运行在容器 B 中,而数据库容器 A 已经通过 `--network-alias db` 起了别名,那么在 Java 应用中,你只需要写:
|
|||
|
|
|||
|
```
|
|||
|
String dbUrl = "jdbc:mysql://db:3306/your_database";
|
|||
|
```
|
|||
|
|
|||
|
而不必关心数据库容器的实际 IP 地址。
|
|||
|
|
|||
|
否则:
|
|||
|
|
|||
|
```
|
|||
|
String dbUrl = "jdbc:mysql://<宿主机IP或localhost>:3306/your_database";
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
因为会通过**宿主机IP映射到容器内**的IP
|
|||
|
|
|||
|
5.连接一个正在运行或已创建的容器到网络
|
|||
|
|
|||
|
接时可以使用 `--alias` 参数为容器在该网络中设置别名
|
|||
|
|
|||
|
```
|
|||
|
docker network connect app-net mysql --alias db
|
|||
|
```
|
|||
|
|
|||
|
6.断开连接
|
|||
|
|
|||
|
```
|
|||
|
docker network disconnect app-net mysql
|
|||
|
```
|
|||
|
|
|||
|
7.删除网络
|
|||
|
|
|||
|
需要注意的是,只有当网络中没有容器连接时才能删除。
|
|||
|
|
|||
|
```
|
|||
|
docker network rm app-net
|
|||
|
docker network prune #删除所有未使用的网络
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
### docker安装:
|
|||
|
|
|||
|
**1.卸载旧版**
|
|||
|
|
|||
|
首先如果系统中已经存在旧的Docker,则先卸载:
|
|||
|
|
|||
|
```Shell
|
|||
|
sudo apt-get remove docker docker-engine docker.io containerd runc
|
|||
|
```
|
|||
|
|
|||
|
**说明**:该命令会删除系统中现有的 Docker 相关包,但不会删除 Docker 镜像、容器、卷等数据。如果需要彻底清理,可以手动删除相关目录。
|
|||
|
|
|||
|
|
|||
|
|
|||
|
**2.安装 Docker 依赖**
|
|||
|
|
|||
|
在安装新版 Docker 前,需要更新 apt 源并安装一些依赖包,以便能够通过 HTTPS 协议访问 Docker 官方仓库。
|
|||
|
|
|||
|
```
|
|||
|
sudo apt-get update
|
|||
|
sudo apt-get install apt-transport-https ca-certificates curl gnupg lsb-release
|
|||
|
```
|
|||
|
|
|||
|
**说明**:这些软件包包括用于 HTTPS 传输的支持库、CA 证书、curl 工具、GPG 密钥管理工具以及 Debian 版本识别工具。
|
|||
|
|
|||
|
|
|||
|
|
|||
|
**3.添加 Docker 官方 GPG 密钥**
|
|||
|
|
|||
|
```
|
|||
|
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
|
|||
|
```
|
|||
|
|
|||
|
**说明**:此命令从 Docker 官方获取 GPG 密钥并保存为二进制格式,供后续验证软件包使用。
|
|||
|
|
|||
|
|
|||
|
|
|||
|
**4.设置 Docker 仓库**
|
|||
|
|
|||
|
使用以下命令将 Docker 稳定版仓库添加到 apt 源列表中:
|
|||
|
|
|||
|
这是最关键的一步,配置docker官方地址,往往**很难下载**!!!
|
|||
|
|
|||
|
```
|
|||
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|||
|
```
|
|||
|
|
|||
|
推荐使用以下阿里云的镜像加速源
|
|||
|
|
|||
|
```
|
|||
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://mirrors.aliyun.com/docker-ce/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|||
|
```
|
|||
|
|
|||
|
cat /etc/apt/sources.list.d/docker.list 可以查看是否配置成功
|
|||
|
|
|||
|
|
|||
|
|
|||
|
**5.安装 Docker Engine**
|
|||
|
|
|||
|
更新 apt 缓存后,安装最新版的 Docker Engine、CLI 工具和 containerd:
|
|||
|
|
|||
|
```
|
|||
|
sudo apt update #如果是docker官方,这一步可能失败!
|
|||
|
sudo apt install docker-ce docker-ce-cli containerd.io
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
**6.启动和校验**
|
|||
|
|
|||
|
```Bash
|
|||
|
# 启动Docker
|
|||
|
systemctl start docker
|
|||
|
# 停止Docker
|
|||
|
systemctl stop docker
|
|||
|
# 重启
|
|||
|
systemctl restart docker
|
|||
|
# 设置开机自启
|
|||
|
systemctl enable docker
|
|||
|
# 执行docker ps命令,如果不报错,说明安装启动成功
|
|||
|
docker ps
|
|||
|
```
|
|||
|
|
|||
|
以上docker安装,最关键的就是**第4步**和**第5步**
|
|||
|
|
|||
|
|
|||
|
|
|||
|
linux vim:
|
|||
|
|
|||
|
**finalshell中粘贴会出现粘贴的文本一行比一行靠右,看起来乱成一团。比较快的解决办法是,在粘贴文档前,在命令行模式下,输入**
|
|||
|
**:set paste**
|
|||
|
|
|||
|
删除全文: 控制模式下 %d
|
|||
|
|
|||
|
|
|||
|
|
|||
|
### docker配置代理
|
|||
|
|
|||
|
```
|
|||
|
sudo vim /etc/systemd/system/docker.service.d/http-proxy.conf
|
|||
|
```
|
|||
|
|
|||
|
```
|
|||
|
[Service]
|
|||
|
Environment="HTTP_PROXY=http://127.0.0.1:7890"
|
|||
|
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
|
|||
|
Environment="NO_PROXY=localhost,127.0.0.1"
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
```
|
|||
|
sudo systemctl daemon-reload //加载配置文件,更新环境变量
|
|||
|
sudo systemctl restart docker
|
|||
|
```
|
|||
|
|
|||
|
```
|
|||
|
systemctl show --property=Environment docker //验证是否配置成功
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
### docker配置镜像:
|
|||
|
|
|||
|
1.编辑 Docker 配置文件,如果该文件不存在,可以创建一个新的文件。
|
|||
|
|
|||
|
```
|
|||
|
sudo vim /etc/docker/daemon.json
|
|||
|
```
|
|||
|
|
|||
|
2.添加多个镜像仓库配置
|
|||
|
|
|||
|
```
|
|||
|
{
|
|||
|
"registry-mirrors": [
|
|||
|
"http://hub-mirror.c.163.com",
|
|||
|
"https://mirrors.tuna.tsinghua.edu.cn",
|
|||
|
"https://ustc-edu-cn.mirror.aliyuncs.com",
|
|||
|
"https://rnsxnws9.mirror.aliyuncs.com",
|
|||
|
"https://registry.docker-cn.com",
|
|||
|
"https://reg-mirror.qiniu.com"
|
|||
|
]
|
|||
|
}
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
3.重启 Docker 服务以应用
|
|||
|
|
|||
|
```
|
|||
|
sudo systemctl restart docker
|
|||
|
```
|
|||
|
|
|||
|
4.验证配置
|
|||
|
|
|||
|
```
|
|||
|
docker info
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
### Dockerfile语法
|
|||
|
|
|||
|
我们只需要告诉Docker,我们的镜像的组成,需要哪些BaseImage、需要拷贝什么文件、需要安装什么依赖、启动脚本是什么,将来Docker会帮助我们构建镜像。
|
|||
|
|
|||
|
而描述上述信息的文件就是Dockerfile文件 。
|
|||
|
|
|||
|
`EXPOSE 8090` 是一个声明性的指令,`EXPOSE` 本身不会进行端口映射
|
|||
|
|
|||
|
在 Dockerfile 中,RUN 指令用于在构建镜像的过程中执行命令,这些命令会在镜像的一个临时容器中执行,然后将执行结果作为新的镜像层保存下来。常见的用途包括安装软件包、修改系统配置、编译代码等。
|
|||
|
|
|||
|
```
|
|||
|
RUN cd $JAVA_DIR \
|
|||
|
&& tar -xf ./jdk8.tar.gz \
|
|||
|
&& mv ./jdk1.8.0_144 ./java8
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
**减少重复构建镜像**
|
|||
|
|
|||
|
当你修改原镜像时,只需使用相同的镜像名执行:
|
|||
|
|
|||
|
```
|
|||
|
docker build -t zbparse .
|
|||
|
```
|
|||
|
|
|||
|
Docker 会根据 **Dockerfile 和上下文的变化**来判断哪些层需要重建,只重建受影响的部分,而未变的层会使用缓存。
|
|||
|
|
|||
|
**优化建议**:
|
|||
|
|
|||
|
- 把变化较少的步骤(如 `FROM` 和设置工作目录和requirements.txt)放在前面。
|
|||
|
- 将容易变化的步骤(比如 `COPY . .`)放在后面。
|
|||
|
|
|||
|
这样,即使修改了 `项目的代码`,其他层仍可复用缓存,从而减少重复构建的开销。
|
|||
|
|
|||
|
|
|||
|
|
|||
|
这样会有一个问题,如果新镜像与旧镜像名字一致,那么旧的镜像名会变成none!
|
|||
|
|
|||
|
以下方法可以删除none镜像。
|
|||
|
|
|||
|
```
|
|||
|
# 查找无标签镜像
|
|||
|
docker images -f "dangling=true"
|
|||
|
# 删除无标签镜像
|
|||
|
docker rmi $(docker images -f "dangling=true" -q)
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
在构建命令中使用 `--no-cache` 选项可以强制 Docker 重新执行所有步骤,这在某些情况下是必要的,但通常应避免使用它以利用缓存。
|
|||
|
|
|||
|
|
|||
|
|
|||
|
### docker启动服务全流程
|
|||
|
|
|||
|
1. 编写dockerfile文件
|
|||
|
|
|||
|
```
|
|||
|
# 使用官方 Python 运行时作为父镜像
|
|||
|
FROM python:3.8-slim
|
|||
|
|
|||
|
# 设置工作目录
|
|||
|
WORKDIR /flask_project
|
|||
|
|
|||
|
# 复制requirements文件到容器中
|
|||
|
COPY requirements.txt .
|
|||
|
|
|||
|
# 关闭pip的进度条以减少日志输出量
|
|||
|
RUN pip config set global.progress_bar off
|
|||
|
|
|||
|
# 安装依赖
|
|||
|
RUN pip install --upgrade pip --default-timeout=200 \
|
|||
|
&& pip install -i https://mirrors.aliyun.com/pypi/simple/ -r requirements.txt
|
|||
|
|
|||
|
# 将当前目录的内容复制到容器的 /flask_project 中
|
|||
|
COPY . .
|
|||
|
|
|||
|
# 将 flask_project 添加到 PYTHONPATH
|
|||
|
ENV PYTHONPATH=/flask_project:$PYTHONPATH
|
|||
|
|
|||
|
|
|||
|
# 暴露端口
|
|||
|
EXPOSE 5000
|
|||
|
|
|||
|
# 在容器启动时运行你的应用
|
|||
|
CMD ["python", "flask_app/run_serve.py"]
|
|||
|
```
|
|||
|
|
|||
|
2. pip freeze > requirements.txt 导出requirements文件
|
|||
|
这里有个问题,这里生成的requirements可能包含诸多不需要的库,有另一种方式。做加法,先pip freeze生成,然后打开项目中的每个文件,查看import的包,手动写requirements,具体的包的版本从pip freeze生成的内容摘取。
|
|||
|
|
|||
|
3. requirements和dockerfile都放在项目的根目录下
|
|||
|
|
|||
|
5. 构造镜像 -t后面是镜像名 ,最后的点号 (`.`) 代表当前目录
|
|||
|
|
|||
|
```
|
|||
|
docker build -t zbparse .
|
|||
|
```
|
|||
|
|
|||
|
5. 运行容器 -p后面,第一个5000代表宿主机端口,第二个5000代表容器内端口 ,zbparse-container为创建的容器名,zbparse是使用的镜像名字
|
|||
|
|
|||
|
```
|
|||
|
docker run -d -p 5000:5000 --name zbparse-container zbparse
|
|||
|
```
|
|||
|
|
|||
|
6. 查看日志 ,若无报错贼容器正常启动
|
|||
|
|
|||
|
```
|
|||
|
docker logs zbparse-container
|
|||
|
docker logs --tail 10 [容器ID或名称] 查看最近10条日志
|
|||
|
docker logs --since 1h [容器ID或名称] 查看最近1小时的日志
|
|||
|
```
|
|||
|
|
|||
|
7. 停止和删除容器,先停止后删除
|
|||
|
|
|||
|
```
|
|||
|
docker stop zbparse-container
|
|||
|
docker rm zbparse-container
|
|||
|
```
|
|||
|
|
|||
|
8. 删除镜像
|
|||
|
|
|||
|
```
|
|||
|
docker rmi zbparse
|
|||
|
```
|
|||
|
|
|||
|
9. 进入容器,可以查看容器内的数据
|
|||
|
|
|||
|
```
|
|||
|
docker exec -it zbparse-container /bin/bash
|
|||
|
```
|
|||
|
|
|||
|
10. 保存镜像为tar文件 (最简单的应该是上传docker hub镜像库,但是现在貌似被墙了)
|
|||
|
|
|||
|
```
|
|||
|
docker save -o zbparse.tar zbparse
|
|||
|
```
|
|||
|
|
|||
|
11. 使用scp传输文件
|
|||
|
|
|||
|
```
|
|||
|
scp zbparse.tar root@118.178.236.139:/home/zy
|
|||
|
```
|
|||
|
|
|||
|
这条命令使用 `scp`(安全复制)将本地生成的 `zbparse.tar` 文件传输到远程服务器 `118.178.236.139` 上,目标路径为 `/home/zy`,使用的登录用户名是 `root`。
|
|||
|
|
|||
|
12. 加载镜像
|
|||
|
|
|||
|
```
|
|||
|
sudo docker load -i zbparse.tar
|
|||
|
```
|
|||
|
|
|||
|
13. 上传镜像
|
|||
|
|
|||
|
```
|
|||
|
docker login #输入邮箱 密码
|
|||
|
docker tag zbparse yourusername/zbparse #标记你的 Docker 镜像
|
|||
|
#其中yourusername/zbparse是标记名
|
|||
|
docker push yourusername/zbparse #推送镜像到 Docker Hub
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
**注意!denied: requested access to the resource is denied**
|
|||
|
|
|||
|
原因:docker hub上只能使用一个命名空间,也就是说
|
|||
|
|
|||
|
docker tag zbparse 646228430smile/zbparse:latest 这里的646228430smile是用户名,保持不变
|
|||
|
|
|||
|

|
|||
|
|
|||
|
14. 查看镜像
|
|||
|
|
|||
|
```
|
|||
|
docker images
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
### **docker可能遇到的问题:**
|
|||
|
|
|||
|
- **linux中构建镜像问题:**
|
|||
|
|
|||
|
```
|
|||
|
RuntimeError: can‘t start new thread。
|
|||
|
```
|
|||
|
|
|||
|
解释原因:线程资源限制: Docker 容器可能有默认或显式设置的资源限制,如 CPU 限制、内存限制和可用线程数限制。在这种情况下,pip 的进度条尝试创建新线程来处理进度条更新,这可能会超出容器允许的线程数上限。
|
|||
|
|
|||
|
解决方法:在dockerfile文件中增加一行关闭pip进度条展示
|
|||
|
RUN pip config set global.progress_bar off
|
|||
|
|
|||
|
|
|||
|
|
|||
|
```
|
|||
|
=> [flask_app internal] load build definition from Dockerfile 0.0s
|
|||
|
=> => transferring dockerfile: 982B 0.0s
|
|||
|
=> ERROR [flask_app internal] load metadata for docker.io/library/python:3.8-slim 60.4s
|
|||
|
------
|
|||
|
> [flask_app internal] load metadata for docker.io/library/python:3.8-slim:
|
|||
|
------
|
|||
|
failed to solve: python:3.8-slim: failed to resolve source metadata for docker.io/library/python:3.8-slim: unexpected status from HEAD request to https://ustc-edu-cn.mirror.aliyuncs.com/v2/library/python/manifests/3.8-slim?ns=docker.io: 403 Forbidden
|
|||
|
exit status 1
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
原因:在构建镜像时,Docker 在尝试从 ustc-edu-cn 镜像站获取 `python:3.8-slim` 镜像的元数据时被拒绝了(403 Forbidden)
|
|||
|
|
|||
|
解决方法:1.单独拉取该镜像 2.添加别的镜像源(可能清华源镜像有问题!!)
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
- **docker运行权限问题**
|
|||
|
|
|||
|
```
|
|||
|
OpenBLAS blas_thread_init: pthread_create failed for thread 1 of 4: Operation not permitted
|
|||
|
OpenBLAS blas_thread_init: RLIMIT_NPROC -1 current, -1 max
|
|||
|
```
|
|||
|
|
|||
|
解决方法:
|
|||
|
|
|||
|
```
|
|||
|
docker run --name zbparse-container --security-opt seccomp=unconfined zbparse
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
## Docker-Compose
|
|||
|
|
|||
|
### docker-compose安装:
|
|||
|
|
|||
|
**方式1:**从 Docker 20.10 开始,Docker 官方就将 Docker Compose 作为插件集成在 Docker Engine 中,所以在安装 Docker Engine 时,它也会一并安装 Docker Compose 插件。无需额外安装
|
|||
|
|
|||
|
验证安装
|
|||
|
|
|||
|
```
|
|||
|
docker compose version
|
|||
|
```
|
|||
|
|
|||
|
**方式2:**安装独立版 Docker Compose 二进制文件
|
|||
|
|
|||
|
下载二进制文件(或者下载别人的镜像复制到服务器中的/usr/local/bin下)
|
|||
|
|
|||
|
```
|
|||
|
sudo curl -L "https://mirrors.aliyun.com/docker-ce/linux/static/stable/x86_64/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
|||
|
```
|
|||
|
|
|||
|
赋予执行权限
|
|||
|
|
|||
|
```
|
|||
|
sudo chmod +x /usr/local/bin/docker-compose
|
|||
|
```
|
|||
|
|
|||
|
验证安装
|
|||
|
|
|||
|
```
|
|||
|
docker-compose --version
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
这两者功能基本一致,大部分命令和参数都是相同的,**只是命令前缀不同**。
|
|||
|
|
|||
|
|
|||
|
|
|||
|
### docker-compose.yml语法
|
|||
|
|
|||
|
**1.services**
|
|||
|
|
|||
|
**常见子配置**:
|
|||
|
|
|||
|
- **image**:指定服务使用的镜像。
|
|||
|
- **build**:指定构建上下文或 Dockerfile 路径。
|
|||
|
- **ports**:映射容器端口到主机端口。
|
|||
|
- **environment**:设置环境变量。
|
|||
|
- **volumes**:挂载主机目录或数据卷到容器。
|
|||
|
- **depends_on**:定义服务启动顺序的依赖关系。
|
|||
|
|
|||
|
**2.networks**
|
|||
|
|
|||
|
定义和管理自定义网络,方便容器间通信。
|
|||
|
|
|||
|
**3.volumes**
|
|||
|
|
|||
|
定义数据卷,用于数据持久化或者在多个容器间共享数据。
|
|||
|
|
|||
|
|
|||
|
|
|||
|
```
|
|||
|
version: '3'
|
|||
|
|
|||
|
services:
|
|||
|
web_app:
|
|||
|
build:
|
|||
|
context: ./web_app # 指定web_app的上下文
|
|||
|
dockerfile: Dockerfile # 在./web_app下寻找Dockerfile
|
|||
|
container_name: web_app
|
|||
|
ports:
|
|||
|
- "8080:80" # 将主机8080端口映射到容器的80端口
|
|||
|
environment:
|
|||
|
- DATABASE_HOST=db
|
|||
|
- DATABASE_USER=root
|
|||
|
- DATABASE_PASSWORD=root
|
|||
|
- DATABASE_NAME=my_database
|
|||
|
depends_on:
|
|||
|
- db
|
|||
|
networks:
|
|||
|
- my_network
|
|||
|
|
|||
|
db:
|
|||
|
image: mysql:8
|
|||
|
container_name: mysql_db
|
|||
|
environment:
|
|||
|
MYSQL_ROOT_PASSWORD: root
|
|||
|
MYSQL_DATABASE: my_database
|
|||
|
ports:
|
|||
|
- "3306:3306"
|
|||
|
volumes:
|
|||
|
- db_data:/var/lib/mysql # 将命名数据卷挂载到MySQL数据目录
|
|||
|
networks:
|
|||
|
- my_network
|
|||
|
restart: always
|
|||
|
|
|||
|
networks:
|
|||
|
my_network:
|
|||
|
driver: bridge # 使用桥接网络驱动
|
|||
|
|
|||
|
volumes:
|
|||
|
db_data:
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
```
|
|||
|
build:
|
|||
|
context: ./web_app
|
|||
|
dockerfile: Dockerfile
|
|||
|
|
|||
|
build: ./web_app #两种写法是等效的
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
****
|
|||
|
|
|||
|
### 4.docker-compose常用命令
|
|||
|
|
|||
|
**构建镜像:**这个命令根据 docker-compose.yml 中各服务的配置构建镜像。如果你修改了 Dockerfile 或者项目代码需要打包进镜像时,就需要运行该命令来构建新的镜像。
|
|||
|
|
|||
|
```
|
|||
|
docker-compose build
|
|||
|
```
|
|||
|
|
|||
|
**启动容器:**这个命令用于启动服务,参数 `-d` 表示以后台守护进程的方式运行。如果镜像不存在,它会自动构建镜像;但如果镜像已经存在,则默认直接使用现有的镜像启动容器。
|
|||
|
|
|||
|
```
|
|||
|
docker-compose up -d
|
|||
|
```
|
|||
|
|
|||
|
**更新并重启容器**
|
|||
|
|
|||
|
```
|
|||
|
docker-compose up --build -d
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
***!!注意在使用docker-compose命令时,可以指定服务名,而无需完整的容器名***
|
|||
|
|
|||
|
|
|||
|
|
|||
|
**查看服务的日志输出**
|
|||
|
|
|||
|
```
|
|||
|
docker-compose logs flask_app --since 1h #只显示最近 1 小时
|
|||
|
```
|
|||
|
|
|||
|
**停止并删除所有由 docker-compose 启动的容器、网络等(默认不影响挂载卷)。**
|
|||
|
|
|||
|
```
|
|||
|
docker-compose down #不能单独指定
|
|||
|
```
|
|||
|
|
|||
|
**删除停止的容器**
|
|||
|
|
|||
|
```
|
|||
|
docker-compose rm
|
|||
|
docker-compose rm flask_app
|
|||
|
```
|
|||
|
|
|||
|
asdf
|
|||
|
|
|||
|
**停止运行的容器**
|
|||
|
|
|||
|
```
|
|||
|
docker-compose stop
|
|||
|
docker-compose stop flask_app #指定某个服务
|
|||
|
```
|
|||
|
|
|||
|
**启动服务**
|
|||
|
|
|||
|
```
|
|||
|
docker-compose start #启动所有停止的..
|
|||
|
docker-compose start flask_app
|
|||
|
```
|
|||
|
|
|||
|
**重启服务(停止+启动)**
|
|||
|
|
|||
|
```
|
|||
|
docker-compose restart
|
|||
|
docker-compose restart flask_app #指定某个服务
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
当使用docker-compose build 构建镜像时,镜像的标签格式通常是 `项目名_服务名`
|
|||
|
|
|||
|
docker-compose up生成的容器名默认是 `项目名_服务名_索引号`
|
|||
|
|
|||
|
**索引号(Index Number)**:这是一个用于区分多个相同服务实例的数字索引。第一次启动时为 `1`,后续实例依次递增。
|
|||
|
|
|||
|
**服务名**是指你在docker-compose中设置的服务名称(services:下的名称)。
|
|||
|
|
|||
|
**项目名**默认是**当前目录名**,如果你使用了 `-p` 选项指定项目名,则使用指定的项目名
|
|||
|
|
|||
|
如
|
|||
|
|
|||
|
```
|
|||
|
docker-compose -p my_custom_project up -d
|
|||
|
```
|
|||
|
|
|||
|
在docker-compose.yml中指定容器名
|
|||
|
|
|||
|
```
|
|||
|
version: '3'
|
|||
|
services:
|
|||
|
web:
|
|||
|
build: .
|
|||
|
container_name: my_custom_web_container
|
|||
|
restart: always 设置自动启动
|
|||
|
ports:
|
|||
|
- "5005:5005"
|
|||
|
db:
|
|||
|
image: mysql:5.7
|
|||
|
container_name: my_custom_db_container
|
|||
|
environment:
|
|||
|
MYSQL_ROOT_PASSWORD: example
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
启动docker-compose中的单独一个服务:docker-compose up -d web web为里面的一个服务名
|
|||
|
|
|||
|
|
|||
|
|
|||
|
### 关于Docker-compose的重要说明
|
|||
|
|
|||
|
**一个Docker-compose文件定义的各个服务默认使用同一个网络**。不同的Docker-compose文件可能使用相同的镜像,如mysql8.0,此时docker会自动进行镜像复用,而不会重复下载。
|
|||
|
|
|||
|
一个**基础镜像可以构造多个容器**,互不影响,
|
|||
|
|
|||
|
```
|
|||
|
db:
|
|||
|
image: mysql:8.0
|
|||
|
environment:
|
|||
|
MYSQL_ROOT_PASSWORD: 123456
|
|||
|
MYSQL_DATABASE: db_project1
|
|||
|
ports:
|
|||
|
- "3306:3306"
|
|||
|
volumes:
|
|||
|
- db_data_project1:/var/lib/mysql
|
|||
|
```
|
|||
|
|
|||
|
```
|
|||
|
db:
|
|||
|
image: mysql:8.0
|
|||
|
environment:
|
|||
|
MYSQL_ROOT_PASSWORD: 123456
|
|||
|
MYSQL_DATABASE: db_project2
|
|||
|
ports:
|
|||
|
- "3307:3306" # 使用不同的主机端口以避免冲突
|
|||
|
volumes:
|
|||
|
- db_data_project2:/var/lib/mysql
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
| **问题类型** | **可能的冲突** | **解决方案** |
|
|||
|
| -------------- | ------------------------------------------ | ------------------------------------------------------------ |
|
|||
|
| **端口冲突** | 容器监听相同的宿主机端口(如 `3306:3306`) | 在不同 `docker-compose.yml` 中映射不同端口(如 `3307:3306`) |
|
|||
|
| **数据卷冲突** | 多个 MySQL 实例共享相同的 `/var/lib/mysql` | 使用不同的 `volume` 名称,或只运行一个 MySQL 实例 |
|
|||
|
| **网络冲突** | 默认网络可能导致 DNS 解析失败 | 在 `docker-compose.yml` 里创建独立的 `network` |
|
|||
|
| **镜像冲突** | 镜像不会冲突,但多个实例可能导致资源竞争 | 镜像可共享,但实例应该使用独立配置 |
|
|||
|
|
|||
|
**最佳实践**
|
|||
|
|
|||
|
1. 如果只需要一个 MySQL 服务,建议让多个 Compose 连接到同一个 MySQL 容器,而不是启动多个 MySQL 容器。
|
|||
|
2. **所有服务都在一个docker-compose中,包括mysql**
|
|||
|
3. 如果必须运行多个 MySQL 实例:
|
|||
|
- 为不同的 MySQL 实例分配不同的宿主机端口(如 `3306`、`3307`)。
|
|||
|
- 使用不同的数据卷,避免数据损坏。
|
|||
|
- 确保不同的实例在不同的 Docker 网络中运行,防止冲突。
|
|||
|
|
|||
|
**最佳实践1:**
|
|||
|
|
|||
|
**让 MySQL 作为一个单独的 Compose 服务**
|
|||
|
|
|||
|
**在其他 `docker-compose.yml` 里连接到这个 MySQL 容器的网络**
|
|||
|
|
|||
|
1.创建一个 Docker 网络
|
|||
|
|
|||
|
```
|
|||
|
docker network create my_shared_network
|
|||
|
```
|
|||
|
|
|||
|
2.创建 MySQL 的 `docker-compose-mysql.yml`
|
|||
|
|
|||
|
```
|
|||
|
version: '3'
|
|||
|
services:
|
|||
|
mysql:
|
|||
|
image: mysql:8
|
|||
|
restart: always
|
|||
|
environment:
|
|||
|
MYSQL_ROOT_PASSWORD: root
|
|||
|
MYSQL_DATABASE: my_database
|
|||
|
ports:
|
|||
|
- "3306:3306"
|
|||
|
networks:
|
|||
|
- my_shared_network
|
|||
|
networks:
|
|||
|
my_shared_network:
|
|||
|
external: true
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
3.在 `docker-compose-app.yml` 里连接这个 MySQL
|
|||
|
|
|||
|
```
|
|||
|
version: '3'
|
|||
|
services:
|
|||
|
web_app:
|
|||
|
image: my_web_app
|
|||
|
environment:
|
|||
|
- DATABASE_HOST=mysql
|
|||
|
- DATABASE_USER=root
|
|||
|
- DATABASE_PASSWORD=root
|
|||
|
- DATABASE_NAME=my_database
|
|||
|
ports:
|
|||
|
- "8080:8080"
|
|||
|
networks:
|
|||
|
- my_shared_network
|
|||
|
networks:
|
|||
|
my_shared_network:
|
|||
|
external: true
|
|||
|
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
| **方式** | **能否被其他容器访问?** | **生效范围** | **优缺点** |
|
|||
|
| ------------------------- | ------------------------ | ----------------------------------------------------- | ------------------------------------------ |
|
|||
|
| **`network-alias`(db)** | ✅ **推荐** | 仅限同一个 `network`(不同compose文件共享网络时也生效) | **最稳定,不受 `container_name` 变更影响** |
|
|||
|
| **`服务名`(mysql)** | ✅ **默认推荐** | 仅限 **同一个**`docker-compose.yml` | **简单,自动解析,不需要额外配置** |
|
|||
|
|
|||
|
|
|||
|
|
|||
|
服务名和网络别名可用于同一网络内容器之间的通信
|
|||
|
|
|||
|
容器名主要用于管理和运维:`docker ps`、`docker logs`、`docker exec` 等命令时指定目标容器。
|
|||
|
|
|||
|
|
|||
|
|
|||
|
4.启动 MySQL 容器
|
|||
|
|
|||
|
```
|
|||
|
docker-compose -f docker-compose-mysql.yml up -d
|
|||
|
```
|
|||
|
|
|||
|
5.启动 Web 应用
|
|||
|
|
|||
|
```
|
|||
|
docker-compose -f docker-compose-app.yml up -d
|
|||
|
```
|
|||
|
|
|||
|
**问题:但你需要确保其他服务不会产生不必要的相互访问,因为相当于都在my_shared_network中。**
|
|||
|
|
|||
|
|
|||
|
|
|||
|
**最佳实践**
|
|||
|
|
|||
|
- **如果所有服务都在同一个 `docker-compose.yml`,直接用 `服务名`(如 `mysql`),因为 Docker Compose 会自动解析。**
|
|||
|
- **如果是多个 `docker-compose.yml` 共享网络,建议用 `network-alias`**,这样即使 `container_name` 改变,服务依然可以正确解析。
|
|||
|
|
|||
|
|
|||
|
|
|||
|
### 实践:部署微服务集群
|
|||
|
|
|||
|
**需求**:将之前学习的cloud-demo微服务集群利用DockerCompose部署
|
|||
|
|
|||
|
|
|||
|
|
|||
|
**实现思路**:
|
|||
|
|
|||
|
① 查看课前资料提供的cloud-demo文件夹,里面已经编写好了docker-compose文件
|
|||
|
|
|||
|
② 修改自己的cloud-demo项目,将数据库、nacos地址都命名为docker-compose中的服务名
|
|||
|
|
|||
|
③ 使用maven打包工具,将项目中的每个微服务都打包为app.jar
|
|||
|
|
|||
|
④ 将打包好的app.jar拷贝到cloud-demo中的每一个对应的子目录中
|
|||
|
|
|||
|
⑤ 将cloud-demo上传至虚拟机,利用 docker-compose up -d 来部署
|
|||
|
|
|||
|
#### compose文件
|
|||
|
|
|||
|
查看课前资料提供的cloud-demo文件夹,里面已经编写好了docker-compose文件,而且每个微服务都准备了一个独立的目录:
|
|||
|
|
|||
|

|
|||
|
|
|||
|
内容如下:
|
|||
|
|
|||
|
```yaml
|
|||
|
version: "3.2"
|
|||
|
|
|||
|
services:
|
|||
|
nacos:
|
|||
|
image: nacos/nacos-server
|
|||
|
environment:
|
|||
|
MODE: standalone
|
|||
|
ports:
|
|||
|
- "8848:8848"
|
|||
|
mysql:
|
|||
|
image: mysql:5.7.25
|
|||
|
environment:
|
|||
|
MYSQL_ROOT_PASSWORD: 123
|
|||
|
volumes:
|
|||
|
- "$PWD/mysql/data:/var/lib/mysql"
|
|||
|
- "$PWD/mysql/conf:/etc/mysql/conf.d/"
|
|||
|
userservice:
|
|||
|
build: ./user-service
|
|||
|
orderservice:
|
|||
|
build: ./order-service
|
|||
|
gateway:
|
|||
|
build: ./gateway
|
|||
|
ports:
|
|||
|
- "10010:10010"
|
|||
|
```
|
|||
|
|
|||
|
可以看到,其中包含5个service服务:
|
|||
|
|
|||
|
- `nacos`:作为注册中心和配置中心
|
|||
|
- `image: nacos/nacos-server`: 基于nacos/nacos-server镜像构建
|
|||
|
- `environment`:环境变量
|
|||
|
- `MODE: standalone`:单点模式启动
|
|||
|
- `ports`:端口映射,这里暴露了8848端口
|
|||
|
- `mysql`:数据库
|
|||
|
- `image: mysql:5.7.25`:镜像版本是mysql:5.7.25
|
|||
|
- `environment`:环境变量
|
|||
|
- `MYSQL_ROOT_PASSWORD: 123`:设置数据库root账户的密码为123
|
|||
|
- `volumes`:数据卷挂载,这里挂载了mysql的data、conf目录,其中有我提前准备好的数据
|
|||
|
- `userservice`、`orderservice`、`gateway`:都是基于Dockerfile临时构建的
|
|||
|
|
|||
|
|
|||
|
|
|||
|
查看mysql目录,可以看到其中已经准备好了cloud_order、cloud_user表:
|
|||
|
|
|||
|

|
|||
|
|
|||
|
查看微服务目录,可以看到都包含Dockerfile文件:
|
|||
|
|
|||
|

|
|||
|
|
|||
|
内容如下:
|
|||
|
|
|||
|
```dockerfile
|
|||
|
FROM java:8-alpine
|
|||
|
COPY ./app.jar /tmp/app.jar
|
|||
|
ENTRYPOINT java -jar /tmp/app.jar
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#### 修改微服务配置
|
|||
|
|
|||
|
因为微服务将来要部署为docker容器,而容器之间互联不是通过IP地址,而是通过容器名。这里我们将order-service、user-service、gateway服务的mysql、nacos地址都修改为基于服务名的访问。
|
|||
|
|
|||
|
如下所示:
|
|||
|
|
|||
|
```yaml
|
|||
|
spring:
|
|||
|
datasource:
|
|||
|
url: jdbc:mysql://mysql:3306/cloud_order?useSSL=false
|
|||
|
username: root
|
|||
|
password: 123
|
|||
|
driver-class-name: com.mysql.jdbc.Driver
|
|||
|
application:
|
|||
|
name: orderservice
|
|||
|
cloud:
|
|||
|
nacos:
|
|||
|
server-addr: nacos:8848 # nacos服务地址
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#### 打包
|
|||
|
|
|||
|
接下来需要将我们的每个微服务都打包。因为之前查看到Dockerfile中的jar包名称都是app.jar,因此我们的每个微服务都需要用这个名称。
|
|||
|
|
|||
|
可以通过修改pom.xml中的打包名称来实现,每个微服务都需要修改:
|
|||
|
|
|||
|
```xml
|
|||
|
<build>
|
|||
|
<!-- 服务打包的最终名称 -->
|
|||
|
<finalName>app</finalName>
|
|||
|
<plugins>
|
|||
|
<plugin>
|
|||
|
<groupId>org.springframework.boot</groupId>
|
|||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
|||
|
</plugin>
|
|||
|
</plugins>
|
|||
|
</build>
|
|||
|
```
|
|||
|
|
|||
|
打包后:
|
|||
|
|
|||
|

|
|||
|
|
|||
|
#### 拷贝jar包到部署目录
|
|||
|
|
|||
|
编译打包好的app.jar文件,需要放到Dockerfile的同级目录中。注意:每个微服务的app.jar放到与服务名称对应的目录,别搞错了。
|
|||
|
|
|||
|
user-service:
|
|||
|
|
|||
|

|
|||
|
|
|||
|
order-service:
|
|||
|
|
|||
|

|
|||
|
|
|||
|
gateway:
|
|||
|
|
|||
|

|
|||
|
|
|||
|
#### 部署
|
|||
|
|
|||
|
最后,我们需要将文件整个cloud-demo文件夹上传到虚拟机中,理由DockerCompose部署。
|
|||
|
|
|||
|
上传到任意目录:
|
|||
|
|
|||
|

|
|||
|
|
|||
|
部署:
|
|||
|
|
|||
|
进入cloud-demo目录,然后运行下面的命令:
|
|||
|
|
|||
|
```sh
|
|||
|
docker-compose up -d
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|