一.下载Docker
理论上来说,直接跟官网就行了,不过这里有个小坑。
官网默认推荐的是Docker Desktop
(一个docker图形化工具)的安装方式,而不是Docker Engine
(docker核心组件)的安装。
正确查看安装文档的方式是官网->Get Started->Docker Engine->CentOS(或其它系统)
,如下图所示。
二、下载镜像
这一步很简单,你项目需要什么镜像,就选择下载什么镜像。例如我使用到了Redis
、Mysql
和Nginx
,访问DockerHub
,然后对应pull
或是直接使用run
命令都能下载镜像。
如果需要特定的版本,可以指定特定的标签。
三、封装自定义app镜像
我们的Spring项目想要在docker容器上运行,就需要封装一个自己的image
,操作起来并不复杂。
1.新建文件夹并上传jar文件
如下图所示,我这里命名为lightcloud-backend
,因为我这里是一个前后端分离项目,这里是后端部分。图片里其余的文件暂时可以忽略。
2.创建Dockerfile文件
Dockerfile
是Docker用于构建镜像的特殊文件,里面声明了构建镜像所需的依赖、镜像运行时执行的命令等等。以下是一个简单的样例,供大家参考。
FROM eclipse-temurin:17
RUN mkdir /opt/app
COPY LightCloud-BackEnd.jar /opt/app
CMD ["java", "-jar", "/opt/app/LightCloud-BackEnd.jar"]
解释一下上述配置的含义:
FROM
表示要构建的镜像依赖的其他镜像,我们这里构建Java应用,需要使用到jdk,选了一个17的版本(tag)。
RUN
表示初始化时需要执行的命令,要在容器内创建一个新的/opt/app
文件夹。
COPY
不必多说,将我们的jar包拷贝到指定位置。
CMD
同样是执行命令,目录下运行Java程序。
3.构建镜像
在当前目录下执行构建就好了,但是注意不要漏掉.
字符。
docker build -t <image_name>:<tag(默认是latest)> .
完成后,你可以在docker image ls
中观察到你的镜像。
四、创建内网并配置Nginx
1.引入
docker的容器默认是bridge
网络模式,这种模式下,每个容器都会有独立且隔离的IP。因而各容器之间的网络通信是一大难题。
一种显而易见的解决方法是,给每个容器添加主机的端口映射,相互之间使用主机的ip和端口进行通信。但是这样弊端不少,首先是大量占用主机端口,容易导致端口冲突等配置问题。其次是不方便,一旦主机端口或是ip发生变更,与之相关的配置全部都要更改。
因而,事实上有更合理的解决方式,那就是创建docker内网。
如果你通过如下命令访问某docker容器内部,下载好ping指令库后让其ping另一台虚拟机,你会发现他们之间是可以ping通的,也就是说,容器之间本来就是相连的。
docker exec -it <container_name or id> /bin/bash
但是仅仅是相连还不够,学过微服务的都知道,不同微服务之间是通过微服务名而非ip进行关联的。如果docker也可以这样关联,灵活性显然大大提高。
答案就是,将Docker容器通过内网连接。
2.连接内网的方法
要将多个Docker容器置于同一内网之中,只需要在容器运行时添加--net
的配置即可
当然首先,我们得创建一个docker内网。
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 my-net
docker run -d --rm --name lightcloud-backend --net my-net lightcloud-backend
通过上面的方式,我们就将容器关联到了内网中,这时候我们再次通过ping指令访问容器名,就能够ping通啦。
3.nginx的配置
我的前端使用的是vue的SPA
(单页面应用),因而我在nginx中需要将前端和后端的路由进行配置,以避免我希望访问前端页面时,被误认为是访问后台资源。
配置如下:
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name lightcloud.io;
location /api {
#root html;
proxy_pass http://lightcloud-backend:8002/api;
# 这个字段是用来让服务器标识原客户端的主机和IP的
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
client_max_body_size 3M; # 对上传路径设置单独的最大文件大小限制
}
location / {
#通过break避免循环匹配
rewrite ^/(.*)$ / break;
proxy_pass http://lightcloud-frontend:8001/;
# 这个字段是用来让服务器标识原客户端的主机和IP的
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location ~ \.(js|css|svg|png|jpg|ico)$ {
#root html;
proxy_pass http://lightcloud-frontend:8001;
# 这个字段是用来让服务器标识原客户端的主机和IP的
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
这里的容器名和端口号自行修改为对应的即可,如果你使用的不是SPA和前后端分离部署,那么配置也会简单很多。
PS:不要忘记Spring项目中也要修改对应的URL为Docker容器名(例如Mysql和Redis)。
Mysql的配置
和Nginx相似,但是mysql默认我们并不需要修改其配置文件,因而需要注意的地方就只有启动命令了。
docker run --name my-mysql -v /opt/mysql-data:/var/lib/mysql -p 3306:3306 --rm -d -e MYSQL_ROOT_PASSWORD=123456 --net my-net mysql
由于mysql
是一个持久型数据库,因而数据的保存十分关键,如果我们不对数据保存进行映射,数据就只会保存到容器中,而容器每次重启,之前的操作都会被清空,这显然十分危险。
这里-v
就是将容器的数据目录映射到了主机的目录,这样,即使我们重启容器,数据也不会丢失。-p
是为了更方便的操作数据,因而映射主机的端口,以便能远程操作数据库。
至于--rm
和-d
,分别是让容器stop后自动清除和容器输出后台运行。
总结
看到这里,基本就能够解决Docker容器的部署问题了,离成功又进了一步!