2-2同步
This commit is contained in:
@@ -1,18 +1,45 @@
|
|||||||
|
# ==================== 安装依赖阶段(构建镜像)====================
|
||||||
# 基础镜像:3.12-slim轻量化,小镜像
|
# 基础镜像:3.12-slim轻量化,小镜像
|
||||||
FROM python:3.12-slim as builder
|
FROM python:3.12-slim AS builder
|
||||||
|
|
||||||
# 构建阶段:隔离构建依赖,最终镜像仅保留运行时,镜像瘦身
|
# 构建阶段:隔离构建依赖,最终镜像仅保留运行时,镜像瘦身
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# 默认测试环境,可通过env修改 development/production
|
|
||||||
ENV PYTHONUNBUFFERED=1 \
|
ENV PYTHONUNBUFFERED=1 \
|
||||||
PYTHONDONTWRITEBYTECODE=1 \
|
PYTHONDONTWRITEBYTECODE=1 \
|
||||||
UV_SYSTEM_PYTHON=1 \
|
UV_SYSTEM_PYTHON=1 \
|
||||||
UV_HTTP_TIMEOUT=600 \
|
UV_HTTP_TIMEOUT=600 \
|
||||||
UV_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple \
|
UV_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple \
|
||||||
UV_EXTRA_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple \
|
UV_EXTRA_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
|
||||||
|
|
||||||
|
# 安装构建依赖
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
gcc \
|
||||||
|
g++ \
|
||||||
|
build-essential \
|
||||||
|
python3-dev \
|
||||||
|
ca-certificates \
|
||||||
|
curl \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& apt-get clean
|
||||||
|
|
||||||
|
# 复制uv和依赖文件
|
||||||
|
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
||||||
|
COPY pyproject.toml uv.lock ./
|
||||||
|
|
||||||
|
# 安装依赖:--frozen锁定版本,--no-dev默认安装生产依赖
|
||||||
|
# 依赖安装到venv,保证隔离性,同时支持uv run调用
|
||||||
|
RUN uv sync --frozen --no-dev
|
||||||
|
|
||||||
|
|
||||||
|
# ==================== 运行时阶段(最终镜像)====================
|
||||||
|
FROM python:3.12-slim AS runtime
|
||||||
|
|
||||||
|
# 默认测试环境,可通过 env 修改
|
||||||
|
ENV PYTHONUNBUFFERED=1 \
|
||||||
|
PYTHONDONTWRITEBYTECODE=1 \
|
||||||
# 可外部覆盖的核心启动参数
|
# 可外部覆盖的核心启动参数
|
||||||
APP_ENV=test \
|
ENV=test \
|
||||||
APP_PORT=8031 \
|
APP_PORT=8031 \
|
||||||
APP_HOST=0.0.0.0 \
|
APP_HOST=0.0.0.0 \
|
||||||
# 是否开启热重载:默认关闭(生产/测试环境不需要),开发环境可设为1
|
# 是否开启热重载:默认关闭(生产/测试环境不需要),开发环境可设为1
|
||||||
@@ -20,32 +47,6 @@ ENV PYTHONUNBUFFERED=1 \
|
|||||||
# 日志配置文件:默认使用json配置,可设为空关闭
|
# 日志配置文件:默认使用json配置,可设为空关闭
|
||||||
APP_LOG_CONFIG=logging_config.json
|
APP_LOG_CONFIG=logging_config.json
|
||||||
|
|
||||||
# 安装构建依赖(仅builder阶段需要,运行时镜像会剔除)
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
||||||
gcc \
|
|
||||||
g++ \
|
|
||||||
build-essential \
|
|
||||||
python3-dev \
|
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
|
||||||
# 清理apt缓存,进一步减小构建层体积
|
|
||||||
&& apt-get clean
|
|
||||||
|
|
||||||
# 复制uv和依赖文件(**核心缓存层**:仅pyproject.toml/uv.lock变更时才重新安装依赖)
|
|
||||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
|
||||||
COPY pyproject.toml uv.lock ./
|
|
||||||
|
|
||||||
# 安装依赖:--frozen锁定版本,--no-dev默认安装生产依赖(开发环境可通过uv sync --dev覆盖)
|
|
||||||
# 依赖安装到venv,保证隔离性,同时支持uv run调用
|
|
||||||
RUN uv sync --frozen --no-dev
|
|
||||||
|
|
||||||
# ==================== 运行时阶段(最终镜像)====================
|
|
||||||
FROM python:3.12-slim as runtime
|
|
||||||
|
|
||||||
# 继承构建阶段的环境变量(可被外部传参覆盖)
|
|
||||||
ENV PYTHONUNBUFFERED=1 \
|
|
||||||
PYTHONDONTWRITEBYTECODE=1 \
|
|
||||||
UV_SYSTEM_PYTHON=1
|
|
||||||
|
|
||||||
# 设置工作目录,与构建阶段一致
|
# 设置工作目录,与构建阶段一致
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
@@ -62,9 +63,5 @@ EXPOSE ${APP_PORT}
|
|||||||
|
|
||||||
# 启动脚本:用shell脚本解析环境变量,动态生成启动命令
|
# 启动脚本:用shell脚本解析环境变量,动态生成启动命令
|
||||||
CMD ["/bin/sh", "-c", \
|
CMD ["/bin/sh", "-c", \
|
||||||
"if [ $APP_RELOAD -eq 1 ]; then \
|
"exec uv run uvicorn app.main:app --host ${APP_HOST} --port ${APP_PORT} --log-config logging_config.json" \
|
||||||
uv run uvicorn app.main:app --host $APP_HOST --port $APP_PORT --reload ${APP_LOG_CONFIG:+-log-config $APP_LOG_CONFIG}; \
|
]
|
||||||
else \
|
|
||||||
uv run uvicorn app.main:app --host $APP_HOST --port $APP_PORT ${APP_LOG_CONFIG:+-log-config $APP_LOG_CONFIG}; \
|
|
||||||
fi" \
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -1,10 +1,54 @@
|
|||||||
# 使用 Nginx 官方轻量镜像
|
# # 使用 Nginx 官方轻量镜像
|
||||||
FROM nginx:1.25-alpine
|
# FROM nginx:1.25-alpine
|
||||||
|
|
||||||
# 拷贝前端构建产物
|
# # 拷贝前端构建产物
|
||||||
COPY dist/ /usr/share/nginx/html/
|
# COPY dist/ /usr/share/nginx/html/
|
||||||
|
|
||||||
# 暴露端口
|
# # 暴露端口
|
||||||
|
# EXPOSE 80
|
||||||
|
|
||||||
|
# CMD ["nginx", "-g", "daemon off;"]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# 第一阶段:构建阶段 - 使用指定node20.15.0版本,安装pnpm
|
||||||
|
FROM node:20.15.0-alpine AS builder
|
||||||
|
|
||||||
|
# 设定工作目录(容器内的项目目录)
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# 配置pnpm源(可选,加速国内安装)
|
||||||
|
ENV PNPM_REGISTRY=https://registry.npmmirror.com/
|
||||||
|
# 全局安装pnpm(node20+推荐corepack管理pnpm,更适配)
|
||||||
|
RUN corepack enable && corepack prepare pnpm@latest --activate
|
||||||
|
|
||||||
|
# 复制包管理文件(先复制lock文件,利用docker层缓存,避免代码变动重复装包)
|
||||||
|
COPY package.json pnpm-lock.yaml* ./
|
||||||
|
|
||||||
|
# 安装项目依赖(--frozen-lockfile 锁定依赖版本,保证构建一致性)
|
||||||
|
RUN pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
# 复制整个项目代码到容器
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# 构建参数:指定构建环境(默认im,可在build时覆盖为test/im/prod等)
|
||||||
|
ARG BUILD_ENV=im
|
||||||
|
# 执行对应环境的构建命令(拼接为pnpm build:xxx)
|
||||||
|
RUN pnpm build:${BUILD_ENV}
|
||||||
|
|
||||||
|
RUN mv /app/dist/main/index.html /app/dist/
|
||||||
|
|
||||||
|
|
||||||
|
# 第二阶段:运行阶段 - 使用官方Nginx稳定版,仅保留dist目录,减小镜像体积
|
||||||
|
FROM nginx:stable-alpine
|
||||||
|
|
||||||
|
# 暴露Nginx默认端口(前端项目常规端口)
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
|
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
# 可选:替换Nginx默认配置(解决前端路由刷新404、开启gzip压缩,优化静态资源)
|
||||||
|
# COPY ./nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
# 从构建阶段(builder)复制构建后的dist目录到Nginx的静态资源根目录
|
||||||
|
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||||
|
|
||||||
|
# Nginx镜像默认会启动nginx,无需额外CMD/ENTRYPOINT
|
||||||
@@ -38,7 +38,7 @@ pipeline {
|
|||||||
)
|
)
|
||||||
choice(
|
choice(
|
||||||
name: 'BUILD_ENV',
|
name: 'BUILD_ENV',
|
||||||
choices: ['im', 's2', 'prod'],
|
choices: ['im', 'prod'],
|
||||||
description: '选择构建的环境配置, 默认为 pnpm build:im 构建'
|
description: '选择构建的环境配置, 默认为 pnpm build:im 构建'
|
||||||
)
|
)
|
||||||
string(
|
string(
|
||||||
@@ -97,6 +97,8 @@ pipeline {
|
|||||||
stage('获取信息') {
|
stage('获取信息') {
|
||||||
steps {
|
steps {
|
||||||
script {
|
script {
|
||||||
|
def cause = currentBuild.getBuildCauses('hudson.model.Cause$UserIdCause')
|
||||||
|
env.ACTUAL_USER = cause ? cause.userName[0] : "系统/自动触发"
|
||||||
// 获取分支名
|
// 获取分支名
|
||||||
env.Code_branch = "${params.Code_branch}"
|
env.Code_branch = "${params.Code_branch}"
|
||||||
// 获取最近一次提交的哈希值(短格式,前8位)
|
// 获取最近一次提交的哈希值(短格式,前8位)
|
||||||
@@ -170,23 +172,6 @@ pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stage('pnpm i&b') {
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
def buildEnv = params.BUILD_ENV // 获取参数
|
|
||||||
sh """
|
|
||||||
export PATH="/data/nvm/versions/node/v20.15.0/bin:$PATH"
|
|
||||||
echo "开始安装依赖包"
|
|
||||||
cd ${WORKSPACE}/ && rm -rf node_modules && pnpm install
|
|
||||||
echo "开始构建"
|
|
||||||
pnpm build:${buildEnv}
|
|
||||||
mv dist/main/index.html dist/
|
|
||||||
chmod -R 755 dist/
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('登录容器') {
|
stage('登录容器') {
|
||||||
steps {
|
steps {
|
||||||
withCredentials([usernamePassword(
|
withCredentials([usernamePassword(
|
||||||
@@ -206,7 +191,7 @@ pipeline {
|
|||||||
script {
|
script {
|
||||||
// 构建镜像,添加标签信息
|
// 构建镜像,添加标签信息
|
||||||
sh """
|
sh """
|
||||||
docker build -t ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${IMAGE_TAG} \
|
docker build -t ${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${IMAGE_TAG} --build-arg BUILD_ENV=${params.BUILD_ENV} \
|
||||||
--label "git-branch='${Code_branch}'" \
|
--label "git-branch='${Code_branch}'" \
|
||||||
--label "git-commit='${GIT_COMMIT_SHORT}'" \
|
--label "git-commit='${GIT_COMMIT_SHORT}'" \
|
||||||
--label "git-author='${GIT_AUTHOR}'" \
|
--label "git-author='${GIT_AUTHOR}'" \
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ pipeline {
|
|||||||
name: 'IMAGE_NAME',
|
name: 'IMAGE_NAME',
|
||||||
description: 'sit 仓库镜像 (除非输入 CUSTOM_IMAGE, 否则使用这里的)',
|
description: 'sit 仓库镜像 (除非输入 CUSTOM_IMAGE, 否则使用这里的)',
|
||||||
registry: 'https://uswccr.ccs.tencentyun.com',
|
registry: 'https://uswccr.ccs.tencentyun.com',
|
||||||
image: 'lessiesit/lessie-review-service',
|
image: 'lessiesit/lessie-email',
|
||||||
credentialId: 'dxin_img_hub_auth',
|
credentialId: 'dxin_img_hub_auth',
|
||||||
filter: '.*',
|
filter: '.*',
|
||||||
defaultTag: '',
|
defaultTag: '',
|
||||||
@@ -26,7 +26,7 @@ pipeline {
|
|||||||
string(
|
string(
|
||||||
name: 'CUSTOM_IMAGE',
|
name: 'CUSTOM_IMAGE',
|
||||||
defaultValue: '',
|
defaultValue: '',
|
||||||
description: '手输完整镜像<registry>/<namespace>/<repo>:<tag>,例如: uswccr.ccs.tencentyun.com/lessiesit/lessie-sourcing-agents:v0.0.1 (填充后,则忽略镜像仓库选择)'
|
description: '手输完整镜像<registry>/<namespace>/<repo>:<tag>,例如: uswccr.ccs.tencentyun.com/lessiesit/lessie-email:v0.0.1 (填充后,则忽略镜像仓库选择)'
|
||||||
)
|
)
|
||||||
booleanParam(
|
booleanParam(
|
||||||
name: 'ROLLBACK_VERSION',
|
name: 'ROLLBACK_VERSION',
|
||||||
@@ -42,11 +42,11 @@ pipeline {
|
|||||||
environment {
|
environment {
|
||||||
LARK_ROBOT = "4b8d66d0-c0f0-4587-b0e5-cff772cb3046" // 飞书机器人ID,用于发送部署通知
|
LARK_ROBOT = "4b8d66d0-c0f0-4587-b0e5-cff772cb3046" // 飞书机器人ID,用于发送部署通知
|
||||||
KUBECONFIG = credentials('k8s-test-config-admin') // k8s 凭证 ID, Jenkins 中配置的凭证名称
|
KUBECONFIG = credentials('k8s-test-config-admin') // k8s 凭证 ID, Jenkins 中配置的凭证名称
|
||||||
Deployment_yaml = "${WORKSPACE}/lessie-ai/sit/s1/lessie-review-service.yaml"
|
Deployment_yaml = "${WORKSPACE}/lessie-ai/sit/s1/lessie-email.yaml"
|
||||||
Deployment_name = "sit-lessie-review-service"
|
Deployment_name = "s1-lessie-email"
|
||||||
K8s_namespace = "sit"
|
K8s_namespace = "sit"
|
||||||
Pod_container_name = "lessie-review-service"
|
Pod_container_name = "lessie-email"
|
||||||
Pod_environment = "sit"
|
Pod_environment = "s1"
|
||||||
}
|
}
|
||||||
stages {
|
stages {
|
||||||
stage('回滚上版') {
|
stage('回滚上版') {
|
||||||
@@ -86,7 +86,7 @@ pipeline {
|
|||||||
def matcher = (customImage =~ imageRegex)
|
def matcher = (customImage =~ imageRegex)
|
||||||
if (!matcher.matches()) {
|
if (!matcher.matches()) {
|
||||||
error "CUSTOM_IMAGE 格式不正确,必须是 registry/namespace/repository:tag 格式\n" +
|
error "CUSTOM_IMAGE 格式不正确,必须是 registry/namespace/repository:tag 格式\n" +
|
||||||
"示例: uswccr.ccs.tencentyun.com/lessiesit/lessie-sourcing-agents:v1.0.0\n" +
|
"示例: uswccr.ccs.tencentyun.com/lessie-ai-web:v1.0.0\n" +
|
||||||
"当前输入: ${customImage}"
|
"当前输入: ${customImage}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,21 +188,25 @@ pipeline {
|
|||||||
sh """
|
sh """
|
||||||
echo "--- Deployment 状态 ---"
|
echo "--- Deployment 状态 ---"
|
||||||
kubectl describe deployment ${Deployment_name} -n ${K8s_namespace} || true
|
kubectl describe deployment ${Deployment_name} -n ${K8s_namespace} || true
|
||||||
|
echo " "
|
||||||
|
|
||||||
echo '--- Pod 列表 ---'
|
echo '--- Pod 列表 ---'
|
||||||
kubectl get pods -n ${K8s_namespace} -l "app=${Pod_container_name},environment=${Pod_environment}" -o wide || true
|
kubectl get pods -n ${K8s_namespace} -l "app=${Pod_container_name},environment=${Pod_environment}" -o wide || true
|
||||||
|
echo " "
|
||||||
|
|
||||||
echo "--- Pod 描述 (describe) ---"
|
echo "--- Pod 描述 (describe) ---"
|
||||||
for pod in \$(kubectl get pods -n ${K8s_namespace} -l "app=${Pod_container_name},environment=${Pod_environment}" -o jsonpath='{.items[*].metadata.name}'); do
|
for pod in \$(kubectl get pods -n ${K8s_namespace} -l "app=${Pod_container_name},environment=${Pod_environment}" -o jsonpath='{.items[*].metadata.name}'); do
|
||||||
echo "-- Pod 描述 \$pod --"
|
echo "-- Pod 描述 \$pod --"
|
||||||
kubectl describe pod \$pod -n ${K8s_namespace} || true
|
kubectl describe pod \$pod -n ${K8s_namespace} || true
|
||||||
done
|
done
|
||||||
|
echo " "
|
||||||
|
|
||||||
echo "--- 最近 200 行 Pod 日志 ---"
|
echo "--- 最近 200 行 Pod 日志 ---"
|
||||||
for pod in \$(kubectl get pods -n ${K8s_namespace} -l "app=${Pod_container_name},environment=${Pod_environment}" -o jsonpath='{.items[*].metadata.name}'); do
|
for pod in \$(kubectl get pods -n ${K8s_namespace} -l "app=${Pod_container_name},environment=${Pod_environment}" -o jsonpath='{.items[*].metadata.name}'); do
|
||||||
echo "-- logs \$pod --"
|
echo "-- logs \$pod --"
|
||||||
kubectl logs \$pod -n ${K8s_namespace} --tail=200 || true
|
kubectl logs \$pod -n ${K8s_namespace} --tail=200 || true
|
||||||
done
|
done
|
||||||
|
echo " "
|
||||||
"""
|
"""
|
||||||
error("=== Deployment 发布失败,请检查以上输出定位问题 ===")
|
error("=== Deployment 发布失败,请检查以上输出定位问题 ===")
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user