分离式部署
针对单体应用的分离式打包+Docker部署。
各类脚本
- 离线安装Docker脚本:docker-install.sh
- 基础环境(redis、postgre-14、nginx)启动脚本:docker-start-multi-container.sh
- 注意:建议更新一下系统时间以确保部分应用的正常运行
sudo ntpdate pool.ntp.org && date
- 注意:建议更新一下系统时间以确保部分应用的正常运行
- 直接部署方式启动脚本:start.sh
- Docker部署方式见下文
有公网情况快速安装基础环境
# 安装Docker
mkdir -p /home/package /home/docker && cd /home/package && \
wget https://download.docker.com/linux/static/stable/x86_64/docker-25.0.4.tgz && \
wget https://raw.githubusercontent.com/yoko-murasame/jeecg-boot/yoko-3.4.3last/docs/DevOps/shell/docker-install.sh && \
chmod +x docker-install.sh && sh -x docker-install.sh
# 安装基础环境
wget https://raw.githubusercontent.com/yoko-murasame/jeecg-boot/yoko-3.4.3last/docs/DevOps/shell/docker-start-multi-container.sh && \
chmod +x docker-start-multi-container.sh && \
vim docker-start-multi-container.sh
# 各种参数目录需要自行修改,pg镜像也需要自己准备
直接部署方式
Jar包运行脚本: start.sh
# 先修改脚本配置, 详情见脚本内容
#启动
sh start.sh start
#停止
sh start.sh stop
#重启
sh start.sh restart
#查看状态
sh start.sh status
Docker部署方式
Dockerfile:
Docker方式部署:
# 防火墙
firewall-cmd --zone=public --add-port=8888/tcp --permanent && firewall-cmd --reload
## 单体应用分离式打包
# 构建容器
docker build -t app-image -f Dockerfile_Separate .
docker save -o ./app-image app-image
# 第一次载入镜像
docker load -i app-image
# 启动
docker run -di --name app-container --restart=unless-stopped -p 9999:8888 -v /application/app:/app -v /application/upFiles:/opt/upFiles app-image
## 超图依赖的应用打包
https://blog.csdn.net/SerikaOnoe/article/details/130337989
如何打包动态链接库?
有时候,项目有Java调用native方法的需求,这时需要依赖.so文件,参考Dockerfile配置:
FROM anapsix/alpine-java:8_server-jre_unlimited
MAINTAINER yoko
# root用户权限
USER root
# 通过镜像源安装tzdata修正容器时区问题
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && apk add --no-cache tzdata
# 时区(无论是否安装tzdata,JDK时区设置下面软链接后,都会更正,但是tzdata不安装会让容器时区不生效)
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 字体(解决流程图部署乱码,请设置好字体目录位置)
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories && apk update && apk --no-cache --purge -U upgrade
RUN apk add --no-cache --purge -uU ttf-dejavu fontconfig && rm -rf /var/cache/apk/* && mkdir -p /usr/share/fonts/new/
# 字体直接打入包中
COPY fonts/*.ttf /usr/share/fonts/new/
RUN fc-cache
# 或者字体挂载出来
# VOLUME /usr/share/fonts/new/
# 文件目录
RUN mkdir -p /opt/upFiles && mkdir -p /opt/webapp
# 工作目录
RUN mkdir -p /so-demo
WORKDIR /so-demo
# 动态链接库.so文件目录
RUN mkdir -p /LD_LIBRARY
# 挂载动态链接库(可选)
VOLUME /LD_LIBRARY
# 或者直接加入容器
# ADD ./lib/path/to/so/* /LD_LIBRARY/
# 动态链接库环境变量,会自动拼接到系统上下文
ENV LD_LIBRARY_PATH /LD_LIBRARY:/opt/jdk1.8.0_202/jre/lib/amd64:/opt/jdk1.8.0_202/jre/lib/amd64/server
EXPOSE 7777
ADD ./target/so-demo.jar ./
CMD sleep 1;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar so-demo.jar
参考启动命令:
docker build -t so-demo .
# --privileged高特权、--user=root以root用户启动
docker run -di --name so-demo --privileged --user=root --restart=unless-stopped -p 7788:7777 -v /path/to/so:/LD_LIBRARY so-demo
修改历史
- 2023-07-13: 新增。
- 2023-07-18: 新增Docker部署方式、传统脚本部署方式、Redis配置
- 2023-09-14: 完善容器启动脚本,注意``参数可能会被html渲染成空字符。
- 2023-10-10: 添加Docker离线安装脚本、Linux分配磁盘空间操作步骤
归档
修改Docker数据默认存储路径
在Linux中,Docker的数据默认存储在/var/lib/docker目录下,包括镜像、容器、卷和网络等数据。如果想将Docker的数据存储在其他磁盘上,可以通过修改Docker的配置文件来实现。
输入 docker info 查看配置 Docker Root Dir,可以看到Docker的数据存储在/var/lib/docker目录下:
首先停止Docker服务:
sudo systemctl stop docker
然后,将/var/lib/docker目录下的数据移动到新的磁盘位置,例如/new_disk/docker:
sudo mv /var/lib/docker /new_disk/docker
接下来,你需要修改Docker的配置文件。在/etc/docker/daemon.json文件中添加data-root配置项,指向新的磁盘位置:
{
"registry-mirrors": ["http://hub-mirror.c.163.com"],
"data-root": "/new_disk/docker"
}
如果/etc/docker/daemon.json文件不存在,你需要创建它。
最后,重新启动Docker服务:
sudo systemctl start docker
现在,Docker的数据应该存储在新的磁盘位置上了。
Redis部署
# 拉取
docker pull redis
# 下载镜像
docker save -o /mnt/d/redis-image redis:latest
# 推送镜像到服务器
# 加载镜像
docker load -i redis-image
# 查看已有镜像
docker images
# 启动,端口63791,密码123456 配置映射 -v /home/redis/redis.conf:/etc/redis/redis.conf
docker run -di --restart=unless-stopped --name=redis \
-p 63791:63791 \
-v /home/redis/data:/data \
redis:latest --requirepass "123456" --port "63791" --appendonly "yes";
# 进入容器
docker exec -it redis /bin/bash
# 测试启动
redis-cli -h 127.0.0.1 -p 63791
auth 123456
set name test
get name
# 通过别的服务器连接测试
curl 127.0.0.1:63791
# curl: (52) Empty reply from server 即连接是通的
基础容器整合脚本
启动:redis、postgre-14、nginx
#!/bin/bash
# 配置容器和镜像名称
container_names=("redis" "postgre-14" "nginx")
image_names=("redis:latest" "postgres-14-zhparser-postgis:1.0" "nginx:latest")
# 创建容器命令数组
create_container_cmds=(
"docker run -di --restart=unless-stopped -p 63791:63791 -v /home/redis/data:/data --name ${container_names[0]} ${image_names[0]} --requirepass "yoko@123" --port "63791" --appendonly "yes""
"docker run -di -e POSTGRES_PASSWORD=yoko@123 -e PGDATA=/var/lib/postgresql/data/pgdata -p 54321:5432 -v /home/postgres/data1:/var/lib/postgresql/data/pgdata --name ${container_names[1]} ${image_names[1]}"
"docker run -di --network=host -v /home/nginx/nginx.conf:/etc/nginx/nginx.conf -v /home/nginx/log:/var/log/nginx -v /home/nginx/conf.d:/etc/nginx/conf.d -v /home/nginx/html:/etc/nginx/html --name ${container_names[2]} ${image_names[2]}"
)
# 启动容器函数
start_container() {
local container_name="$1"
echo "启动 $container_name 容器..."
docker start "$container_name"
echo "$container_name 容器已启动。"
}
# 停止容器函数
stop_container() {
local container_name="$1"
echo "停止 $container_name 容器..."
docker stop "$container_name"
echo "$container_name 容器已停止。"
}
# 重启容器函数
restart_container() {
local container_name="$1"
echo "重启 $container_name 容器..."
docker restart "$container_name"
echo "$container_name 容器已重启。"
}
# 检查容器状态 -f '\{\{.State.Status\}\}'
container_status() {
local container_name="$1"
# docker container inspect --format='' $container_name
docker inspect -f '' "$container_name" 2>/dev/null
}
# 根据用户输入的参数调用相应的功能
if [ "$1" == "start" ]; then
# 启动容器
for ((i=0; i<${#container_names[@]}; i++)); do
container_name="${container_names[i]}"
image_name="${image_names[i]}"
create_container_cmd="${create_container_cmds[i]}"
if [ -z "$(container_status "$container_name")" ]; then
echo "创建 $container_name 容器..."
eval "$create_container_cmd"
echo "$container_name 容器已创建并启动。"
elif [ "$(container_status "$container_name")" == "exited" ]; then
start_container "$container_name"
elif [ "$(container_status "$container_name")" == "running" ]; then
echo "$container_name 容器已经在运行中。"
fi
done
elif [ "$1" == "stop" ]; then
# 停止容器
for container_name in "${container_names[@]}"; do
if [ -n "$(container_status "$container_name")" ] && [ "$(container_status "$container_name")" == "running" ]; then
stop_container "$container_name"
else
echo "$container_name 容器未运行。"
fi
done
elif [ "$1" == "restart" ]; then
# 重启容器
for container_name in "${container_names[@]}"; do
if [ -n "$(container_status "$container_name")" ] && [ "$(container_status "$container_name")" == "running" ]; then
restart_container "$container_name"
else
echo "$container_name 容器未运行,无法重启。"
fi
done
else
echo "无效的参数。请使用 'start'、'stop' 或 'restart'。"
fi
Linux Docker离线安装脚本
一键脚本
目录结构:
/
├─home
│ ├─package 安装包路径
│ │ ├─docker-20.tgz 安装包
│ │ ├─docker-install.sh 安装脚本
│ ├─docker 应用安装路径(存储各种镜像、容器等数据)
脚本:
#!/bin/bash
#安装包路径 https://download.docker.com/linux/static/stable/x86_64/
package_path="/home/package"
#应用安装路径(存储各种镜像、容器等数据,默认docker的存储路径为/data/docker0)
install_path="/home/docker"
#docker安装包名
docker_inatall_name=$(find . -name "*docker*.tgz" | grep -oE '[^/]+\.tgz$')
# 检查是否有root权限
if [ "$EUID" -ne 0 ]
then echo "请使用root权限运行此脚本"
exit
fi
cd $package_path
# 安装docker
if command -v docker &> /dev/null; then
echo "----------Docker 已经安装----------"
else
DOCKER_FILE_PATH="$install_path/docker"
echo "----------开始安装docker----------"
cd $package_path
tar -xvf $docker_inatall_name -C $package_path
cp docker/* /usr/bin/
rm -rf $package_path/docker
echo "[Unit]" >> /etc/systemd/system/docker.service
echo "Description=Docker Application Container Engine" >> /etc/systemd/system/docker.service
echo "Documentation=https://docs.docker.com" >> /etc/systemd/system/docker.service
echo "After=network-online.target firewalld.service" >> /etc/systemd/system/docker.service
echo "Wants=network-online.target" >> /etc/systemd/system/docker.service
echo "" >> /etc/systemd/system/docker.service
echo "[Service]" >> /etc/systemd/system/docker.service
echo "Type=notify" >> /etc/systemd/system/docker.service
echo "ExecStart=/usr/bin/dockerd --graph $DOCKER_FILE_PATH" >> /etc/systemd/system/docker.service
echo "ExecReload=/bin/kill -s HUP \$MAINPID" >> /etc/systemd/system/docker.service
echo "LimitNOFILE=infinity" >> /etc/systemd/system/docker.service
echo "LimitNPROC=infinity" >> /etc/systemd/system/docker.service
echo "LimitCORE=infinity" >> /etc/systemd/system/docker.service
echo "TimeoutStartSec=0" >> /etc/systemd/system/docker.service
echo "Delegate=yes" >> /etc/systemd/system/docker.service
echo "KillMode=process" >> /etc/systemd/system/docker.service
echo "Restart=on-failure" >> /etc/systemd/system/docker.service
echo "StartLimitBurst=3" >> /etc/systemd/system/docker.service
echo "StartLimitInterval=60s" >> /etc/systemd/system/docker.service
# Reload systemd daemon and restart Docker
echo "----------注册docker服务----------"
chmod +x /etc/systemd/system/docker.service
systemctl daemon-reload
echo "----------启动docker服务----------"
systemctl start docker.service
echo "----------设置服务开机自启----------"
systemctl enable docker.service
echo "----------docker安装完毕----------"
fi
执行脚本:
cd /home
sh -x docker-install.sh
其他配置:
# 以下配置会增加一段自定义内网 IPv6 地址,开启容器的 IPv6 功能,以及限制日志文件大小,防止 Docker 日志塞满硬盘
sudo cat > /etc/docker/daemon.json <<EOF
{
"log-driver": "json-file",
"log-opts": {
"max-size": "20m",
"max-file": "3"
},
"ipv6": true,
"fixed-cidr-v6": "fd00:dead:beef:c0::/80",
"experimental":true,
"ip6tables":true
}
EOF
Linux Docker离线安装步骤
参考:这里
1)下载docker官方离线包
安装包官方地址:https://download.docker.com/linux/static/stable/x86_64/
2)解压安装包
tar -zxvf docker-20.10.8.tgz
sudo cp docker/* /usr/bin/
3)注册docker为service服务
默认docker的存储路径为/data/docker0
如需修改请修改docker.service
ExecStart=/usr/bin/dockerd --graph=/data/docker0
在/etc/systemd/system/目录下新增docker.service文件
# sudo vi /etc/systemd/system/docker.service
输入内容
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
# 如果有搭建私有镜像仓库,--insecure-registry设置为私有镜像仓库地址。
ExecStart=/usr/bin/dockerd --graph /home/docker0
ExecReload=/bin/kill -s HUP $MAINPID
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
# Uncomment TasksMax if your systemd version supports it.
# Only systemd 226 and above support this version.
#TasksMax=infinity
TimeoutStartSec=0
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes
# kill only the docker process, not all processes in the cgroup
KillMode=process
# restart the docker process if it exits prematurely
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s
[Install]
WantedBy=multi-user.target
4)启动docker
# 赋予docker.service 执行权限
chmod +x /etc/systemd/system/docker.service
# 重载配置文件以生效
systemctl daemon-reload
# 启动docker
sudo systemctl start docker
# 设置服务开机自启
sudo systemctl enable docker.service
# 查看服务状态
systemctl status docker
5)普通用户执行dockers命令
用户组配置文件:/ect/group 即用户组的所有信息都存放在此文件中。
# 新建用户组 docker,如果用户组已经存在则跳过
sudo groupadd docker
# 将 appuser用户添加到 docker 组
gpasswd -a appuser docker
# 更新用户组
newgrp docker
# 修改docker.sock用户组权限
chown root:docker /var/run/docker.sock
# 切换普通用户,验证docker命令是否能执行
su - admin
docker version
Docker多容器启动脚本
#!/bin/bash
# 配置容器和镜像名称
container_names=("redis-test" "mysql-test")
image_names=("redis" "mysql")
# 创建容器命令数组
create_container_cmds=("docker run -d --name ${container_names[0]} ${image_names[0]}"
"docker run -d --name ${container_names[1]} ${image_names[1]}")
# 启动容器函数
start_container() {
local container_name="$1"
echo "启动 $container_name 容器..."
docker start "$container_name"
echo "$container_name 容器已启动。"
}
# 停止容器函数
stop_container() {
local container_name="$1"
echo "停止 $container_name 容器..."
docker stop "$container_name"
echo "$container_name 容器已停止。"
}
# 重启容器函数
restart_container() {
local container_name="$1"
echo "重启 $container_name 容器..."
docker restart "$container_name"
echo "$container_name 容器已重启。"
}
# 检查容器状态
container_status() {
local container_name="$1"
docker inspect -f '' "$container_name" 2>/dev/null
}
# 根据用户输入的参数调用相应的功能
if [ "$1" == "start" ]; then
# 启动容器
for ((i=0; i<${#container_names[@]}; i++)); do
container_name="${container_names[i]}"
image_name="${image_names[i]}"
create_container_cmd="${create_container_cmds[i]}"
if [ -z "$(container_status "$container_name")" ]; then
echo "创建 $container_name 容器..."
eval "$create_container_cmd"
echo "$container_name 容器已创建并启动。"
elif [ "$(container_status "$container_name")" == "exited" ]; then
start_container "$container_name"
elif [ "$(container_status "$container_name")" == "running" ]; then
echo "$container_name 容器已经在运行中。"
fi
done
elif [ "$1" == "stop" ]; then
# 停止容器
for container_name in "${container_names[@]}"; do
if [ -n "$(container_status "$container_name")" ] && [ "$(container_status "$container_name")" == "running" ]; then
stop_container "$container_name"
else
echo "$container_name 容器未运行。"
fi
done
elif [ "$1" == "restart" ]; then
# 重启容器
for container_name in "${container_names[@]}"; do
if [ -n "$(container_status "$container_name")" ] && [ "$(container_status "$container_name")" == "running" ]; then
restart_container "$container_name"
else
echo "$container_name 容器未运行,无法重启。"
fi
done
else
echo "无效的参数。请使用 'start'、'stop' 或 'restart'。"
fi
Docker单容器启动脚本
#!/bin/bash
# 配置容器和镜像名称
container_name="redis-test"
image_name="redis"
# 创建容器命令
create_container_cmd="docker run -d --name $container_name $image_name"
# 启动容器函数
start_container() {
echo "启动 $container_name 容器..."
docker start "$container_name"
echo "$container_name 容器已启动。"
}
# 停止容器函数
stop_container() {
echo "停止 $container_name 容器..."
docker stop "$container_name"
echo "$container_name 容器已停止。"
}
# 重启容器函数
restart_container() {
echo "重启 $container_name 容器..."
docker restart "$container_name"
echo "$container_name 容器已重启。"
}
# 检查容器状态
container_status=$(docker inspect -f '' "$container_name" 2>/dev/null)
# 根据用户输入的参数调用相应的功能
if [ "$1" == "start" ]; then
# 启动容器
if [ -z "$container_status" ]; then
echo "创建 $container_name 容器..."
eval "$create_container_cmd"
echo "$container_name 容器已创建并启动。"
elif [ "$container_status" == "exited" ]; then
start_container
elif [ "$container_status" == "running" ]; then
echo "$container_name 容器已经在运行中。"
fi
elif [ "$1" == "stop" ]; then
# 停止容器
if [ -n "$container_status" ] && [ "$container_status" == "running" ]; then
stop_container
else
echo "$container_name 容器未运行。"
fi
elif [ "$1" == "restart" ]; then
# 重启容器
if [ -n "$container_status" ] && [ "$container_status" == "running" ]; then
restart_container
else
echo "$container_name 容器未运行,无法重启。"
fi
else
echo "无效的参数。请使用 'start'、'stop' 或 'restart'。"
fi
Linux分配磁盘空间
当我们有多块磁盘时,可能需要将不同的目录挂载到不同磁盘上,这时需要通过重新分配目录挂载实现,这里以 /root 目录为例:
首先查看 /root 目录的挂载情况:
# 查看目录占用情况
du -sh /root
------------
5.0G /root
# 查看/root挂载情况
df -Th /root
------------
/dev/vda1 xfs 25G 5.0G 20G 20% /root
# 查看所有磁盘空间
df -Th
------------
/dev/vda1 xfs 25G 5.0G 20G 20% /boot
/dev/vdb1 xfs 200G 0.0G 200G 0% /root
可以看到磁盘 /dev/vdb1 是空闲的,而当前 /root 目录挂载到了 /dev/vda1 磁盘,因此我们需要进行修改。
要将空闲空间分配给 /root 目录,按照以下步骤进行操作:
1)首先备份重要的数据。在进行分区和文件系统操作之前,备份是非常重要的,以防止数据丢失。
2)将空闲空间挂载到一个临时目录:创建一个临时目录,例如 /mnt/temp,并将空闲空间 /dev/vdb1 挂载到该目录:
mkdir /mnt/temp
mount /dev/vdb1 /mnt/temp
3)复制 /root 目录的内容:使用 rsync 命令将 /root 目录的内容复制到临时目录:
rsync -avxHAX /root/ /mnt/temp/
这将确保所有文件和权限都被正确复制到临时目录。
4)卸载原来的 /root 目录:卸载原来的 /root 目录,确保没有其他进程或服务正在使用该目录:
umount /root
5)挂载空闲空间到 /root 目录:将空闲空间重新挂载到 /root 目录:
mount /dev/vdb1 /root
6)更新 /etc/fstab 文件:打开 /etc/fstab 文件,并将原来指向 /root 的行修改为:
# ext4是文件系统类型,需要根据实际修改
/dev/vdb1 /root ext4 defaults 0 0
# 实际可能长这样:/data目录是这个磁盘原先挂载的目录,对应的文件系统类型为xfs
/dev/vdb1 /data xfs defaults 0 0
保存文件并关闭。
7)重新启动系统:为了确保所有更改生效,重新启动系统:
reboot
系统重启后,会看到 /root 目录现在位于空闲空间 /dev/vdb1 上。