记录新手使用docker部署微服务的一次实操过程
一、服务器安装docker
Docker 安装命令
# 1. 安装必要的软件包
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 1.1 这一步如果执行失败,可以尝试替换centos 仓库地址
##### 备份
sudo cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
##### 编辑配置文件
sudo vi /etc/yum.repos.d/CentOS-Base.repo
##### 修改仓库地址为阿里云镜像源
将mirrorlist字段注释掉(如果存在),并添加或修改baseurl字段,指向国内镜像站点的地址。
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra
baseurl=https://mirrors.aliyun.com/centos/$releasever/os/$basearch/
##### 清理缓存并测试地址
sudo yum clean all
sudo yum makecache
# 2. 设置镜像源
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 3. 更新 yum 软件包索引
sudo yum makecache fast
# 4. 安装docker CE
## 4.1 目前国内镜像源被封,在安装时会无法下载,需要修改配置文件,执行下面的命令
vi /etc/docker/daemon.json
## 4.2 插入下面的代码
{
"registry-mirrors" :
[
"https://docker.m.daocloud.io",
"https://docker.jianmuhub.com",
"https://huecker.io",
"https://dockerhub.timeweb.cloud",
"https://dockerhub1.beget.com",
"https://noohub.ru"
]
}
## 4.3 清理yum
sudo yum clean all
## 4.4 更新yum 缓存
sudo yum makecache
## 4.5 安装docker CE
sudo yum install -y docker-ce docker-ce-cli
# 5. 启动docker 服务
sudo systemctl start docker
# 6. 设置docker 开机自启动
sudo systemctl enable docker
二、中间件安装
包含Nginx、RabbitMQ、XXL-Job
Nginx 安装
#1 rpm包的获取
wget http://nginx.org/packages/centos/7/x86_64/RPMS/nginx-1.20.1-1.el7.ngx.x86_64.rpm
#2 安装
rpm -ivh nginx-1.20.1-1.el7.ngx.x86_64.rpm
#3 查看安装版本
[root@nginx-test app]# nginx -v
nginx version: nginx/1.20.1
#4 查看都指定了哪些参数
[root@nginx-test app]# nginx -V
#5 查看默认安装路径
[root@nginx-test app]# find / -name nginx
#8 设置开机自启
sudo systemctl enable nginx
要使用自定义配置文件启动Nginx,只需完成以下两个步骤:
- 创建nginx.conf文件并保存至目标目录
- 执行以下启动命令(请将路径替换为实际配置文件位置):
nginx -c /usr/local/nginx/conf/nginx.conf
RabbitMq 安装
# 拉取镜像
docker pull rabbitmq:management
# 创建容器
docker volume create rabbitmq-home
## 这个容器的物理位置可以使用 docker volume inspect rabbitmq-home 命令来查看
## 一般来说在:/var/lib/docker/volumes/rabbitmq-home/_data
# 使用docker 安装
docker run -id --name=rabbitmq --restart always -v rabbitmq-home:/var/lib/rabbitmq -p 15672:15672 -p 5672:5672 -e RABBITMQ_DEFAULT_USER=rmq -e RABBITMQ_DEFAULT_PASS=123456 rabbitmq:management ## 这里将刚才上一步创建的volume容器挂载到docker里,并且使用-p暴露了两个端口,及设定了两个环境变量:
## 15672端口:RabbitMQ的管理页面端口
## 5672端口:RabbitMQ的消息接收端口
## RABBITMQ_DEFAULT_USER环境变量:指定RabbitMQ的用户名,这里我指定为rmq
## RABBITMQ_DEFAULT_PASS环境变量:指定RabbitMQ的密码,这里我指定为123456
我的项目中rabbitMQ还需要安装一个插件,才能保证正常运行。
rabbitmq_delayed_message_exchange 插件安装
插件下载地址:https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases
# 查看docker中安装的rabbitMq 版本
docker exec -it rabbitMQ容器ID bash
# 查看版本
rabbitmqctl version
# 将刚刚上传的插件拷贝到容器内plugins目录下,rabbit是容器的name,也可以使用容器id
docker cp /root/rabbitmq_delayed_message_exchange-3.13.0.ez rabbitmq:/plugins
# 进入到RabbitMQ容器内部
docker exec -it rabbitmq /bin/bash
# 查看插件是否存在
root@my-rabbit:/# cd plugins
root@my-rabbit:/plugins# ls | grep delay
# 启用插件(注意是在plugins内)
root@my-rabbit:/plugins# rabbitmq-plugins enable rabbitmq_delayed_message_exchange
# 从容器中退出
root@my-rabbit:/plugins# exit
# 重启RabbitMQ容器
docker restart rabbit
Xxl-job 安装命令
# 拉取镜像
docker pull xuxueli/xxl-job-admin:2.4.1
# 查看镜像
docker images
# 创建容器外置宿主机文件目录
mkdir -p /data/xxl-job-admin/data/applogs/xxl-job
mkdir -p /data/xxl-job-admin/tmp
# 创建容器并启动
docker run --name xxl-job-admin --restart=always -e PARAMS="--spring.datasource.url=jdbc:mysql://k8s-bj-test-nodeports.ruijie.com.cn:31585/middleware_data?Unicode=true&characterEncoding=UTF-8 --spring.datasource.username=system --spring.datasource.password=b904d8c987dd49bc9926906eed3323a1 --server.port=8080 --server.servlet.context-path=/xxl-job-admin" -p 8080:8080 -v /tmp:/data/xxl-job-admin/tmp -v /data/xxl-job-admin/data/applogs/xxl-job:/data/applogs/xxl-job -v /data/xxl-job-admin/tmp:/tmp -d xuxueli/xxl-job-admin:2.4.1
上述命令最后创建容器并启动时,将数据库链接地址和账号密码替换为你自己的。
三、应用服务部署
-
创建DockerFile 文件
FROM openjdk:8-jdk
LABEL maintainer="111(111@ruijie.com.cn)"
# 设置时区(需同时配置系统时区和JVM时区)
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone && \
mkdir -p /opt/projects/ictcloud
WORKDIR /opt/projects/ictcloud
COPY ict-cloud-cms-api.jar cms-api.jar
# 添加JVM时区参数
CMD java -jar -Duser.timezone=Asia/Shanghai \
-Xms2048m -Xmx2048m -Xss512k \
-XX:SurvivorRatio=8 -XX:+UseG1GC \
cms-api.jar
在 Docker 镜像构建过程中设置时区时,如果仅使用 RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 命令,可能会出现时间不准确的问题,主要原因和解决方案如下:
-
缺少时区配置文件:
- 需要同时配置
/etc/timezone文件 - 完整命令示例:
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo "Asia/Shanghai" > /etc/timezone
- 需要同时配置
-
基础镜像差异:
- 不同 Linux 发行版对时区的处理方式不同
- 对于 Alpine 镜像需要额外安装 tzdata 包:
RUN apk add --no-cache tzdata \ && ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo "Asia/Shanghai" > /etc/timezone
-
容器与宿主机时间同步:
- 建议在运行容器时挂载宿主机的
/etc/localtime:docker run -v /etc/localtime:/etc/localtime:ro ...
- 建议在运行容器时挂载宿主机的
-
多阶段构建注意事项:
- 如果在多阶段构建中设置时区,需确保最终阶段也包含时区配置
-
应用层时间处理:
- 某些应用(如 Java 应用)可能需要额外配置:
ENV TZ=Asia/Shanghai
最佳实践是在 Dockerfile 中同时设置符号链接和 timezone 文件,并根据实际运行环境考虑是否需要挂载宿主机的时区文件。对于关键业务系统,建议在容器启动时验证系统时间是否正确。
-
服务打包,将jar包和DockerFile上传到指定的目录下
要将JAR包与Dockerfile分离存放,可通过调整Dockerfile中的COPY指令路径实现。以下是具体实现方式:
示例目录结构:
project/
├── docker/
│ └── Dockerfile
└── target/
└── app.jar
Dockerfile修改方案:
# 相对路径方案(推荐)
COPY ../target/app.jar /app/app.jar
# 绝对路径方案
COPY /home/user/project/target/app.jar /app/app.jar
构建镜像注意事项:
- 使用相对路径时,需在项目根目录执行构建命令:
docker build -f docker/Dockerfile -t myapp .
关键说明:
- 相对路径中".."表示上级目录
- Linux系统使用正斜杠(/)作为路径分隔符
- 构建时的工作目录会影响路径解析
- 生产环境建议采用明确的路径指定方式
可选替代方案:
- 通过--build-arg参数动态传递JAR路径
- 采用多阶段构建,在构建阶段生成JAR包
- 在CI/CD流程中预先部署JAR文件
-
构建服务镜像,注意需要切换到DockerFile文件所在的目录下
docker build -t ict-cloud-cms-api::latest
-
运行容器
docker run -d -p 9000:9000 \
-e SPRING_CLOUD_NACOS_DISCOVERY_IP=172.16.3.208 \
-e SPRING_CLOUD_NACOS_DISCOVERY_SERVER-ADDR=172.16.3.208:8848 \
--name cms-api --restart always ict-cloud-cms-api::latest
-
检查是否启动,执行命令 docker ps -a
如果觉得每次更新服务都要重新创建镜像,停止服务,启动服务太繁琐。也可以创建一个可执行文件,文件放在与dockerfile 统一目录下。
#!/bin/bash
# 定义服务参数
IMAGE_NAME="ict-cloud-cms-api"
CONTAINER_NAMES=("ict-cloud-cms-api1" "ict-cloud-cms-api2" "ict-cloud-cms-api3" "ict-cloud-cms-api4")
LOG_PATHS=("/home/logs/ict-cloud-cms-api1/logs/" "/home/logs/ict-cloud-cms-api2/logs/"
"/home/logs/ict-cloud-cms-api3/logs/" "/home/logs/ict-cloud-cms-api4/logs/")
NACOS_PORTS=("9200" "9201" "9202" "9208")
SERVER_IP="10.44.32.86"
DOCKERFILE_PATH="./Dockerfile" # 假设Dockerfile在当前目录
# 1. 停止并删除旧容器
echo "正在停止并移除旧容器..."
for name in "${CONTAINER_NAMES[@]}"; do
docker stop $name 2>/dev/null && docker rm $name 2>/dev/null
done
# 2. 删除旧镜像
echo "正在删除旧镜像..."
docker rmi ${IMAGE_NAME}:latest 2>/dev/null
# 3. 重新构建镜像
echo "正在构建新镜像..."
docker build -t ${IMAGE_NAME}:latest -f ${DOCKERFILE_PATH} .
# 4. 启动新容器
echo "正在启动新容器..."
for i in "${!CONTAINER_NAMES[@]}"; do
docker run -d --restart always \
--network host \
--name ${CONTAINER_NAMES[$i]} \
-v ${LOG_PATHS[$i]}:/opt/projects/ictcloud/logs/ \
-e SERVER_PORT=${NACOS_PORTS[$i]} \
-e spring.cloud.nacos.discovery.port=${NACOS_PORTS[$i]} \
-e spring.cloud.nacos.discovery.ip=${SERVER_IP} \
${IMAGE_NAME}:latest
done
# 5. 验证部署结果
echo -e "\n部署结果验证:"
docker images | grep ${IMAGE_NAME}
docker ps --filter "name=ict-cloud-cms-api" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
在上面的可执行命令中,我是一次性启动了四个服务,并分别指定了对应的端口,你可以根据自己的真实需求进行修改。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)