spring boot
项目docker
部署指南
概述
通过docker部署应用和微服务是目前的主流,本教程根据作者部署项目的亲身实践进行编写。如果您初次接触docker,可能会觉得这样部署比较麻烦,因为需要了解container(容器)、image(镜像)、dockerfile、docker-compose等概念。可以先放下这些概念,直接按本教程的描述进行部署。通过体验之后,会发docker部署应用的好处很多,再进行docker系统的学习。
注意:本教程是基于albaba cloud linux 3 云服务器环境,centos7 通用。
1 云服务器安装docker
通过ssh登陆云服务器,推荐终端神器mobaxterm(谁用谁说好)。shell环境直接输入下面的命令进行安装:
# 1、yum 包更新到最新
yum update
# 2、安装需要的软件包, yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的
yum install -y yum-utils device-mapper-persistent-data lvm2
# 3、 设置yum源
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 4、 安装docker,出现输入的界面都按 y
yum install -y docker-ce
# 5、 查看docker版本,验证是否验证成功
docker -v
2 启动docker服务,并设置开机启动
直接复制,shell环境直接输入下面的命令:
systemctl start docker
systemctl enable docker
3 docker镜像加速设置(本步骤可以省略!)
注册一个属于自己的阿里云账户(可复用淘宝账号),用支付宝扫码登陆阿里云。找到“容器镜像服务”->“镜像工具”->“镜像加速器”,然后看到自己独立的镜像加速地址和centos操作文档。根据操作文档,复制到shell进行粘贴就行。
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://'你自己的加速地址,不要直接复制'.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
4 使用docker拉取nginx、Redis、mysql镜像
直接复制,shell环境直接输入下面的命令:
docker pull mysql:5.7 # 5.7 是指定版本号
docker pull redis:5.0 # 5.0 是指定版本号
docker pull nginx # 这里没写版本号,意思是拉取最新的版本
docker images # 查看本机所有镜像
5 使用docker相关命令操作container(本步骤可以省略!主要是熟悉一下container的相关操作)
5.1 使用docker run命令命令建立并运行container
由于我们已经获取了mysql的镜像,可以用docker run命令启动一下服务进行初步的体验。补充一下概念,可以把image(镜像)类比为java的类文件,container(容器)理解为对象,而docker run命令为new关键字。每一个container(容器)都是一个微小的虚拟机,有自己的网络地址和端口。这里以nginx和mysql为例。shell环境直接输入下面的命令:
### 运行nginx
docker run --name c_nginx -p 80:80 -d nginx #用nginx镜像启动名字为 c_nginx 容器实例后台运行(-d),并且把本机(宿主机)的80端口(-p)映射到c_nginx容器的80端口
### 下面来个稍微复杂点的
docker run -d \
-p 3306:3306 \
--name=c_mysql \
-v ~/mysql/conf:/etc/mysql/conf.d \
-v ~/mysql/logs:/logs \
-v ~/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--privileged=true mysql:5.7
上面复杂命令的解释:
docker run -d \
-p 3306:3306
–name=c_mysql
-~/mysql/conf:/etc/mysql/conf.d \ # 这里的 -v 意思是挂载(共享)宿主机的 ~/mysql/conf 文件夹作为c_mysql容器的/etc/mysql/conf.d
-~/mysql/logs:/logs \ # 用以实现文件同步和保存。因为容器如果被删除掉,宿主机还保存着相应的数据
-v ~/mysql/data:/var/lib/mysql
-e MYSQL_ROOT_PASSWORD=123456 \ # 设置root密码
–privileged=true mysql:5.7 # --privileged=true 设置容器的文件权限。注意这里的镜像mysql:5.7和拉取的镜像一致,使用了版本号。
可以通过docker COMMAND --help
命令自行学习,例如:docker run --help
5.2 使用docker exec命令命令进入container
docker exec -it c_nginx /bin/bash # 进入刚才建立的c_nginx容器
docker exec -it c_mysql /bin/bash # 进入刚才建立的c_mysql容器
可以通过docker exec --help
自行了解-it
的参数作用。
5.3 其它常用docker操作container的命令
docker ps -a # 查看所有容器。-a 意思是包括已经停止的容器。
docker stop c_nginx # 停止c_nginx容器
docker start c_nginx # 运行c_nginx容器
docker restart c_nginx # 重新运行c_nginx容器
docker logs 4358e2ad63d5 # 4358e2ad63d5 为 c_nginx容器的id。docker ps 命令可以看到。
docker inspect 4358e2ad63d5 # 查看容器的详细信息
docker cp c_nginx:/etc/nginx/ ~/nginx/conf/ # 从c_nginx容器里面复制文件到宿主机
6 准备 nginx container 的运行环境
nginx需要特别对待一下。这个步骤的主要目的是从一个临时容器里面获取nginx的配置文件。
mkdir ~/mall-app/nginx -p
# 1. 先建立一个临时nginx容器
docker run --name c_nginx -p 80:80 -d nginx
# 2.
#复制临时nginx容器的文件到主机
docker cp c_nginx:/etc/nginx/ ~/mall-app/nginx/conf/
docker cp c_nginx:/usr/share/nginx/html/ ~/mall-app/nginx/html/
docker cp c_nginx:/var/log/nginx/ ~/mall-app/nginx/logs
# 3.
docker rm -f "nginx容器id" # docker ps 命令可以得到nginx容器id
这样操作之后就在~/mall-app/nginx
文件夹里面保存了一个完整的nginx服务相关的文件。为什么多此一举?因为在接下来通过docker-compse批量启动容器的时候,会把nginx container的/etc/nginx
目录挂载为宿主机的~/mall-app/nginx/conf
。这时如果宿主机的~/mall-app/nginx/conf
文件夹是空的,会覆盖掉c_nginx:/etc/nginx
,造成nginx 容器启动失败。当然也有其它解决办法,个人比较喜欢这样做。
7 修改boot程序的环境配置,并进行打包
由于在docker环境下boot jar包
、nginx
、mysql
、Redis
都是以微服务的方式运行(就是在独立的container里面运行),每个container有独立的ip地址,并且不是固定的,因此在相应的配置文件中用到ip地址的地方就要改成服务名称!这点非常重要!
7.1 修改mall-app模块的application.yml
application.yml文件按照下面进行修改:
server:
port: 8088
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://mysql:3306/mall-app?serverTimezone=UTC
username: root
password: jn@run@2022
type: com.alibaba.druid.pool.DruidDataSource
redis:
database: 0
# host: 127.0.0.1
host: redis
port: 6379
# 密码(默认为空)
password:
# 连接超时时长(毫秒)
timeout: 6000ms
这样修改之后,原来配置文件中的localhost
或者127.0.0.1
就改成了服务名称mysql
和redis
。为什么是这个两个指定的名称?因为在后面的步骤的编写docker-compose
文件时候会对服务名称mysql
和redis
进行定义。
7.2 通过idea的maven进行打包
直接点击idea maven 功能区的 package 按钮,等待打包完成,找到mall-app-0.0.1-SNAPSHOT.jar
这个文件。
8 编写dockerfile文件生成镜像
通过dockerfile
可以自定义镜像。在第上面使用docker
拉取nginx
、Redis
、mysql
的步骤中,拉取的镜像都是官方已有的。想要定义自己的微服务镜像,就需要先编写dockerfile
。
先建立一个工作目录:
mkdir ~/mall-docker
把mall-app-0.0.1-SNAPSHOT.jar
这个文件上传到云服务的这个目录,然后编写mall-app-dockfile
文件。
FROM openjdk:11
ADD mall-app-0.0.1-SNAPSHOT.jar mall-app.jar
CMD java -jar mall-app.jar
EXPOSE 8088
编写完dockerfile
就可以在当前文件夹下用命令docker build -f ./mall-app-dockfile -t mall-app-img .
生成自定义镜像了。这里我们直接跳过这一步,因为可以在下面的docker-compose
文件中直接用脚本生成镜像,并直接运行容器。
9 编写docker-compose文件启动所有服务
9.1 安装docker-compose
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
9.2 编写docker-compose文件
本教程的核心就是下面这个docker-compose.yml
文件!在~/mall-docker
的目录下新建docker-compose.yml
文件,并把下面的代码复制并保存。注意,这里文件名必须为docker-compose.yml
。还需注意的是在下面的配置中我们定义了一个个服务mall-app
,千万不要使用下划线这样定义为mall_app
!。这里有个很大的坑一会再说!
version: "3"
services:
nginx:
image: nginx
container_name: c_nginx
ports:
- 80:80
volumes:
- ~/mall-app/nginx/conf/:/etc/nginx/
- ~/mall-app/nginx/html/:/usr/share/nginx/html/
- ~/mall-app/nginx/logs:/var/log/nginx/
networks:
- mall-app_net
depends_on:
- mall-app
mall-app:
image: mall-app-img
build:
context: ./
dockerfile: mall-app-dockfile
container_name: c_mall_app
ports:
- "8088:8088"
networks:
- mall-app_net
depends_on:
- redis
- mysql
redis:
image: redis:5.0
container_name: c_redis_app
ports:
- "6379:6379"
volumes:
- ~/mall-app/redis/redis.conf:/etc/redis/redis.conf
- ~/mall-app/redis/data:/data
networks:
- mall-app_net
command: redis-server /etc/redis/redis.conf
mysql:
image: mysql:5.7
container_name: c_mysql_5_7_app
environment:
MYSQL_ROOT_PASSWORD: '123456'
ports:
- "3306:3306"
volumes:
- ~/mall-app/mysql/data:/var/lib/mysql
- ~/mall-app/mysql/conf:/etc/mysql/conf.d
- ~/mall-app/mysql/logs:/logs
networks:
- mall-app_net
command: --default-authentication-plugin=mysql_native_password #解决外部无法访问
networks:
mall-app_net:
这时~/mall-docker
的目录结构如下:
~/mall-docker
├── docker-compose.yml
├── mall-app-dockfile
└── mall-app.jar
最后cd ~/mall-docker
目录,执行docker-compose up -d
,观察控制台输出的日志。如果没有什么问题,使用docker ps -a
看一下相4个服务是否启动。
10 设置mysql配置文件,并导入sql脚本生成数据库数据
先编写一下mysql
的配置文件。由于在上面的docker-compose.yml
文件中定义mysql
服务的时候有这一行- ~/mall-app/mysql/conf:/etc/mysql/conf.d
,我们只需输入下面命令即可:
cd ~/mall-app/mysql/conf
vi my.cnf # 把下面的配置复制过来就行
[client]
default_character_set=utf8
host = localhost
user = root
password = 123456
#database = test
[mysqld]
character_set_server=utf8
collation_server=utf8_general_ci
#port = 3306
[mysql]
default_character_set=utf8
docker restart 7f13f2cf0821 # 7f13f2cf0821为mysql容器的id。docker ps 命令可以看到。
# docker logs 7f13f2cf0821 # 如果启动失败,通过该命令查看日志
注意:这里的文件名为my.cnf
,不要写成my.ini
;里面的类似default_character_set=utf8
的配置不要写成default-character-set=utf8
,都是踩过的坑和教训,说多了都是泪!
然后通过sftp把微同商城的两个sql脚本platform-mall-MySQL.sql
、platform-mall-MySQL.sql-activiti.sql
也上传到~/mall-app/mysql/conf
目录。继续输入命令:
docker exec -it 7f13f2cf0821 /bin/bash
进入mysql容器后,输入mysql
直接进入数据库的shell。为什么不需要用mysql -uroot -p
输入密码?因为我们在刚才的my.cnf
中已经进行了配置。
然后在mysql的shell环境下执行下面命令:
mysql> create database mall-app;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-plus' at line 1
然后你得到上面的报错,自己开始怀疑人生了。恭喜,又入坑了!不要慌,使用mall-app
加上反单引号就可以了,别问我怎么知道的,都是泪。
create database `mall-app`;
use mall-app;
source /etc/mysql/conf.d/mall-app-MySQL.sql;
11 编写nginx的配置文件,进行端口映射
同样由于在上面的docker-compose.yml
文件中定义nginx
服务的时候有这一行- ~/mall-app/nginx/conf/:/etc/nginx/
,
我们只需在宿主机上面:
cd ~/mall-app/nginx/conf/conf.d/
mv default.conf default.conf_bak
vim mall.conf
把下面的配置内容保存到mall.conf
:
server {
listen 80;
#server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
location /mall-app {
proxy_pass http://mall-app:8088;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
然后用docker restart "nginx容器的id"
命令重启服务,并用curl根据情况进行测试。因为在写本教程的时候,域名还没申请好所以在上面的配置中还没有进行域名的相关配置。特别需要注意的是proxy_pass http://mall-app:8088
一定不要写成proxy_pass http://mall_app:8088
,否则nginx代理的时候会出错!这也是在“9 编写docker-compose文件启动所有服务 ”步骤中定义服务名称千万不要用下划线的原因!还是那句话,说多了都是泪。
docker restart e7acb5e9aec8
curl localhost # 现在还没部署管理后台的前端,这里现在应该是打印nginx主页的信息
curl curl localhost/mall-app/doc.html # 正常应该打印微同商城swagger首页的html代码
12 打包前端,静态部署到nginx
用vscode
打开mall-app
文件夹,然后进行下面的操作:
执行命令:
npm install
# 构建生产环境
npm run build
先备份一下~/mall-app/nginx/html
目录里面原有的文件,然后把mall-app
->dist
目录下的所有文件上传到~/mall-app/nginx/html
。~/mall-app/nginx/html
目录最终为下面这个样子:
[root@iZuf63zu4bo54nzzdqs9akZ html]# ls
2210241102 50x.html_bak config index.html index.html_bak
进行测试,看一下是否能访问管理后台的页面
curl localhost # 这里现在应该是打印”微同软件管理平台”信息
docker部署boot微服务安装基本完成!
13 重新上传jar包注意的问题
重新打包并上传jar的时候需要:注意必须先执行docker-compse build
,再执行docker-compse up -d
。否则docker-compse
不会使用新的jar包建立镜像!
学习资料参考:
- docker官网:http://www.docker.com
- Docker Hub官网: https://hub.docker.com/
- 【尚硅谷2022版Docker实战教程(docker教程天花板)】 https://www.bilibili.com/video/BV1gr4y1U7CY?p=75&share_source=copy_web&vd_source=d9ce631f6c235cba374ea8d94b3b4606
- 作者:姬广超,微信:newchoose,个人网站:www.jiguangchao.com(网站已经停了,过段时间进行部署)