本地推荐使用第一种,线上推荐使用第二种方式
1. 第一种方式本机编译golang可执行文件
deploy.sh
#!/bin/sh
name=$1
version=$2
logs="/apps/$name/logs"
conf="/apps/$name/config"
if [ ! -d $logs ];then
mkdir -p $logs
fi
if [ ! -d $conf ];then
mkdir -p $conf
fi
go build main.go
docker build -f Dockerfile3 -t $name:$version .
rm -f main
docker rm $name -f
# --add-host=myhost:192.168.1.100
docker run --name $name -p 8080:8080 -v $logs:/apps/logs -v $conf:/apps/config -d $name:$version
config目录下的配置文件记得copy一份到挂载目录
cp ./config/* /apps/xxxx/config
dockerfile
# 表示依赖 alpine 最新版
FROM alpine:latest
LABEL MAINTAINER="Joker"
LABEL EMAIL="xxx@qq.com"
ENV VERSION 1.0
# 在容器根目录 创建一个 apps 目录
WORKDIR /apps
# 挂载容器目录
VOLUME ["/apps/config"]
VOLUME ["/apps/logs"]
# 可执行文件拷贝当前目录下
ADD main /apps/main
# 拷贝配置文件到容器中
COPY config /apps/config
# COPY logs /apps/logs
# 设置时区为上海
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
# 设置时区(以 Asia/Shanghai 为例)
RUN apk add --no-cache tzdata
ENV TZ=Asia/Shanghai
# 设置编码
ENV LANG C.UTF-8
# 暴露端口
EXPOSE 8080
# 运行golang程序的命令
CMD ["./main"]
2. 第二种方式,使用容器编译
- 此方式的好处是本机不需要golang环境,而且打包出来的容器大小和第一种方式一样
- deploy.sh
#!/bin/sh
set -x
name=$1
version=$2
mode=$3
logs="/tmp/apps/$name/logs"
conf="/tmp/apps/$name/config"
if [ ! -d $logs ];then
sudo mkdir -p $logs
fi
if [ ! -d $conf ];then
sudo mkdir -p $conf
fi
if [ -z "$name" ] || [ -z "$version" ] || [ -z "$mode" ]; then
echo "请依次输入 项目名称 版本号 部署环境"
exit 1
fi
# git操作
sudo chmod 777 -R .git/
git pull
# go build main.go
sudo docker build -f Dockerfile3 -t $name:$version .
# 判断是否存在名为 "xxx" 的容器
if sudo docker ps -a --format '{{.Names}}' | grep -q "$name"; then
# 停止并删除容器
sudo docker stop "$name"
sudo docker rm "$name" -f
echo "${name}容器已停止"
fi
# 获取当前版本镜像的 ID
current_image_id=$(sudo docker images -q $name:$version)
# 之前版本镜像都删掉
sudo docker images | awk -v name="$name" -v version="$version" -v current_image_id="$current_image_id" '$1 == name && $2 != version && $3 != current_image_id { print $3 }' | xargs -I {} sudo docker rmi {}
# # 之前版本镜像也都删掉
# if sudo docker images -q $name; then
# sudo docker rmi $(docker images -q $name)
# echo "${name}镜像已删除"
# fi
# conf暂时不挂载
sudo docker run --name $name -p 8080:8080 -v $logs:/apps/logs -e Mode="$mode" -d $name:$version
# docker run --name $name -p 8080:8080 -v $logs:/apps/logs -v $conf:/apps/config -d $name:$version
# docker run --name $name -p 8080:8080 \
# --mount type=bind,source=$logs,target=/apps/logs \
# --mount type=bind,source=$conf,target=/apps/config \
# -d $name:$version
dockerfile
FROM golang:1.20.5-alpine as builder
# 这里在docker里也使用go module的代理服务
ENV GOPROXY https://goproxy.cn,direct
ENV GO111MODULE on
# 在容器根目录 创建一个 apps 目录
RUN mkdir -p /apps
# 设置工作目录
WORKDIR /apps
COPY . /apps
## 编译
RUN go build -o /apps/main ./main.go
# ============================================================
# ============================================================
# ======================= 运行应用 ============================
# ============================================================
# ============================================================
# 表示依赖 alpine 最新版
FROM alpine:latest
LABEL MAINTAINER="Joker"
LABEL EMAIL="xxxx@qq.com"
ENV VERSION 1.0
# 在容器根目录 创建一个 apps 目录
RUN mkdir -p /apps
# 设置工作目录
WORKDIR /apps
# 挂载容器目录
VOLUME ["/apps/config"]
VOLUME ["/apps/logs"]
# 可执行文件拷贝当前目录下
COPY --from=builder /apps/main /apps/main
# 拷贝配置文件到容器中
COPY --from=builder /apps/config /apps/config
# COPY --from=builder logs /apps/logs
# 设置时区为上海
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone
# 设置时区(以 Asia/Shanghai 为例)
RUN apk add --no-cache tzdata
ENV TZ=Asia/Shanghai
# 设置编码
ENV LANG C.UTF-8
# 暴露端口
EXPOSE 8080
# 运行golang程序的命令
CMD ["./main"]
sh脚本太多了怎么办,那就放到一个shell里面
#!/bin/bash
function show_help {
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " --mode=<mode> Set the mode (local, dev, test, prod)"
echo " --v=<version> Set the version number"
echo " --name=<name> Set the project name"
echo " --help Show this help message"
}
# 保存输入的参数
args=("$@")
# 使用 shift 命令去除已处理的位置参数
shift
# 处理命令行参数
for ((i = 0; i < "${#args[@]}"; i++)); do
case "${args[$i]}" in
--mode=*|-mode=*)
mode="${args[$i]#*=}"
;;
--mode|-mode)
mode="${args[$((i+1))]}"
;;
--v=*|-v=*)
version="${args[$i]#*=}"
;;
--v|-v)
version="${args[$((i+1))]}"
;;
--name=*|-name=*)
name="${args[$i]#*=}"
;;
--name|-name)
name="${args[$((i+1))]}"
;;
--help)
show_help
exit 0
;;
esac
done
if [ -z "$name" ]; then
echo "请输入项目名称"
exit 1
fi
# 检查 mode 是否合法
valid_modes=("" "local" "dev" "test" "prod")
valid=false
for valid_mode in "${valid_modes[@]}"; do
if [ "$mode" = "$valid_mode" ]; then
valid=true
break
fi
done
# 如果 mode 不在合法的模式值中,则输出错误信息
if ! $valid; then
echo "mode值只能是:空值 local, dev, test, prod."
exit 1
fi
cd ../entry_manage
logs="/apps/$name/logs"
conf="/apps/$name/config"
if [ ! -d $logs ]; then
sudo mkdir -p $logs
fi
if [ ! -d $conf ]; then
sudo mkdir -p $conf
fi
# git操作
echo "更新代码..."
# sudo chmod 777 -R .git/
# git pull
function setVersoin {
# 获取上一个镜像版本
previous_version=$(docker images | awk '$1 == "'${name}'" && $2 != "latest" {print $2}' | sort -rV | head -n 1)
if [ -z "$previous_version" ]; then
# 如果没有上一个版本,则默认设置为 1.0.0
version="1.0.0"
else
# 去除可能存在的 "v" 字符串
version_without_v=$(echo "$previous_version" | sed 's/^v//')
# 将上一个版本的主版本号、次版本号和修订号分离出来
major=$(echo "$version_without_v" | awk -F'.' '{print $1}')
minor=$(echo "$version_without_v" | awk -F'.' '{print $2}')
patch=$(echo "$version_without_v" | awk -F'.' '{print $3}')
# 递增修订号,如果修订号超过 10,则递增次版本号
patch=$((patch + 1))
if [ "$patch" -ge 10 ]; then
patch=0
minor=$((minor + 1))
fi
# 如果次版本号超过 10,则递增主版本号
if [ "$minor" -ge 10 ]; then
minor=0
major=$((major + 1))
fi
# 更新新版本号
version="$major.$minor.$patch"
fi
}
if [ -z "$version" ]; then
setVersoin
fi
echo "项目:${name} 版本:${version} 环境:${mode}"
function deploy1 {
sudo docker build -f Dockerfile -t $name:$version .
sudo docker rm $name -f
sudo docker run --name $name -p 8088:8080 -v $logs:/apps/logs -e Mode="$mode" -d $name:$version
}
function deploy2 {
rm -f main
go build -o main main.go
docker build -f Dockerfile2 -t $name:$version .
rm -f main
docker rm $name -f
docker run --name $name -p 8088:8080 -v $logs:/apps/logs -e Mode="$mode" -d $name:$version
}
function deploy3 {
sudo docker build -f Dockerfile3 -t $name:$version .
# 判断是否存在名为 "xxx" 的容器
if sudo docker ps -a --format '{{.Names}}' | grep -q "$name"; then
# 停止并删除容器
sudo docker stop "$name"
sudo docker rm "$name" -f
echo "${name}容器已停止"
fi
# 获取当前版本镜像的 ID
current_image_id=$(sudo docker images -q $name:$version)
# 之前版本镜像都删掉
# sudo docker images | awk -v name="$name" -v version="$version" -v current_image_id="$current_image_id" '$1 == name && $2 != version && $3 != current_image_id { print $3 }' | xargs -I {} sudo docker rmi {}
# conf暂时不挂载
sudo docker run --name $name -p 8088:8080 -v $logs:/apps/logs -e Mode="$mode" -d $name:$version
}
echo "请选择dockerfile:"
echo "1. Dockerfile"
echo "2. Dockerfile2"
echo "3. Dockerfile3"
# 使用 read 命令读取用户输入,并将输入的值赋给变量 choice
read -p "请输入选项的序号: " choice
# 根据用户输入的值进行不同的处理
case $choice in
1) deploy1 ;;
2) deploy2 ;;
3) deploy3 ;;
*) echo "无效的选项。" ;;
esac
使用sh脚本
# 自动递增版本
./deploy.sh --name xxx -mode=local
# 指定镜像版本打包
./deploy.sh --name xxx -v=1.0
# 自动递增版本、不指定环境变量
./deploy.sh --name xxx
# 指定版本、指定环境
./deploy.sh --name xxx -v=1.0 -mode=local