PHP信创=国产容器平台PHP镜像制作与信创环境分发部署完整方案
·
国产容器平台PHP镜像制作与信创环境分发部署完整方案
一、先搞清楚整体是什么
你要做的事情,用大白话说就是:
把PHP政务系统打包成一个"集装箱"(Docker镜像)
然后放到国产的"港口"(镜像仓库)
再分发到各个"码头"(信创服务器)上运行
涉及的国产平台:
镜像仓库:Harbor(开源,政务常用)/ 华为SWR / 阿里ACR
容器平台:华为CCE / 阿里ACK / 国产OpenShift替代品 KubeSphere
底层OS: 麒麟OS / 统信UOS(ARM鲲鹏 或 x86)
CPU架构: x86_64 或 aarch64(ARM,鲲鹏/飞腾)
---
二、整体流程图
开发机(Windows/Mac)
│
│ 1. 写Dockerfile
│ 2. docker build 构建镜像
│
▼
本地镜像
│
│ 3. docker tag 打标签
│ 4. docker push 推送
│
▼
Harbor私有镜像仓库(内网)
│
├──────────────────────────────┐
│ │
▼ ▼
x86服务器 ARM鲲鹏服务器
(麒麟OS x86) (麒麟OS aarch64)
│ │
│ 5. docker pull │ 5. docker pull
│ 6. docker run │ 6. docker run
▼ ▼
PHP政务系统运行中 PHP政务系统运行中
---
三、关键难点:ARM架构兼容问题
信创最大的坑就是这个:
普通Docker镜像(x86)在ARM鲲鹏服务器上跑不起来!
就像Windows软件装不到Mac M1上一样。
解决方案有两种:
方案A:构建多架构镜像(一个镜像同时支持x86和ARM)← 推荐
方案B:分别构建x86镜像和ARM镜像,分开管理
本方案用方案A,一次构建,到处运行。
---
四、目录结构(先建好)
gov-approval/
├── docker/
│ ├── php/
│ │ ├── Dockerfile # PHP应用镜像
│ │ ├── php.ini # PHP配置
│ │ ├── php-fpm.conf # PHP-FPM配置
│ │ └── supervisord.conf # 进程管理
│ ├── nginx/
│ │ ├── Dockerfile # Nginx镜像
│ │ └── gov_approval.conf # Nginx配置
│ └── dameng/
│ └── Dockerfile # 达梦数据库镜像(可选)
├── deploy/
│ ├── docker-compose.yml # 本地开发用
│ ├── docker-compose.prod.yml # 生产环境用
│ ├── k8s/ # Kubernetes部署文件
│ │ ├── namespace.yaml
│ │ ├── configmap.yaml
│ │ ├── secret.yaml
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── ingress.yaml
│ └── scripts/
│ ├── build.sh # 构建脚本
│ ├── push.sh # 推送脚本
│ └── deploy.sh # 部署脚本
├── src/ # PHP业务代码
└── public/
└── index.php
---
五、PHP应用镜像 Dockerfile(核心)
# 文件: docker/php/Dockerfile
# 大白话:这个文件告诉Docker怎么一步步造出我们的PHP镜像
# ============================================================
# 第一阶段:安装Composer依赖(构建阶段,不进最终镜像)
# 好处:最终镜像不包含Composer工具,体积更小
# ============================================================
FROM php:8.2-cli-alpine AS composer-stage
# 安装Composer
COPY --from=composer:2.6 /usr/bin/composer /usr/bin/composer
WORKDIR /app
# 先只复制依赖文件(利用Docker缓存层,代码没变时不重新装依赖)
COPY composer.json composer.lock ./
# 安装PHP依赖(不装dev依赖,生产环境用不到)
RUN composer install \
--no-dev \
--no-scripts \
--no-autoloader \
--prefer-dist \
--optimize-autoloader
# 复制全部代码,生成autoload
COPY . .
RUN composer dump-autoload --optimize --no-dev
# ============================================================
# 第二阶段:构建最终运行镜像
# 基础镜像选php:8.2-fpm-alpine,体积小,支持多架构
# alpine是一个超小的Linux,只有5MB
# ============================================================
FROM php:8.2-fpm-alpine AS production
# 设置时区为中国时区(政务系统必须)
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
&& echo $TZ > /etc/timezone
# 安装系统依赖
# --no-cache 不缓存,减小镜像体积
RUN apk add --no-cache \
nginx \
supervisor \
curl \
libpng-dev \
libjpeg-turbo-dev \
freetype-dev \
libzip-dev \
oniguruma-dev \
libxml2-dev \
icu-dev \
tzdata
# 安装PHP扩展
RUN docker-php-ext-configure gd \
--with-freetype \
--with-jpeg \
&& docker-php-ext-install -j$(nproc) \
pdo \
pdo_mysql \
mbstring \
xml \
zip \
gd \
intl \
opcache \
bcmath
# 安装Redis扩展(通过PECL)
RUN apk add --no-cache --virtual .build-deps $PHPIZE_DEPS \
&& pecl install redis-6.0.2 \
&& docker-php-ext-enable redis \
&& apk del .build-deps \
&& rm -rf /tmp/pear
# ============================================================
# 安装达梦DM8 PHP驱动(信创关键步骤)
# 注意:达梦驱动需要从达梦官网下载,这里假设已放到docker/php/drivers/
# ============================================================
# 复制达梦驱动文件
COPY docker/php/drivers/pdo_dm.so /tmp/pdo_dm.so
# 根据架构选择对应驱动(多架构构建时自动选择)
RUN PHP_EXT_DIR=$(php -r "echo ini_get('extension_dir');") \
&& cp /tmp/pdo_dm.so ${PHP_EXT_DIR}/pdo_dm.so \
&& echo "extension=pdo_dm.so" > /usr/local/etc/php/conf.d/pdo_dm.ini \
&& rm /tmp/pdo_dm.so
# 复制PHP配置文件
COPY docker/php/php.ini /usr/local/etc/php/php.ini
COPY docker/php/php-fpm.conf /usr/local/etc/php-fpm.d/www.conf
# 复制Nginx配置
COPY docker/nginx/gov_approval.conf /etc/nginx/http.d/default.conf
# 复制Supervisor配置(同时管理nginx和php-fpm两个进程)
COPY docker/php/supervisord.conf /etc/supervisord.conf
# 创建运行用户(不用root运行,安全)
RUN addgroup -g 1000 www \
&& adduser -u 1000 -G www -s /bin/sh -D www
# 设置工作目录
WORKDIR /var/www/html
# 从第一阶段复制代码和依赖(不复制Composer工具本身)
COPY --from=composer-stage --chown=www:www /app /var/www/html
# 创建必要目录并设置权限
RUN mkdir -p storage/logs storage/cache storage/uploads \
&& chown -R www:www storage \
&& chmod -R 775 storage
# 暴露端口(Nginx监听80)
EXPOSE 80
# 健康检查(K8s用来判断容器是否正常)
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost/health || exit 1
# 启动命令:用supervisor同时启动nginx和php-fpm
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]
---
六、配置文件
6.1 PHP配置
; 文件: docker/php/php.ini
[PHP]
; 基础设置
memory_limit = 256M
max_execution_time = 300
max_input_time = 300
post_max_size = 50M
upload_max_filesize = 50M
default_charset = UTF-8
; 时区
date.timezone = Asia/Shanghai
; 错误处理(生产环境不显示错误,写日志)
display_errors = Off
log_errors = On
error_log = /var/www/html/storage/logs/php_error.log
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
; OPcache(PHP代码缓存,提升性能)
[opcache]
opcache.enable = 1
opcache.memory_consumption = 128
opcache.interned_strings_buffer = 8
opcache.max_accelerated_files = 10000
opcache.revalidate_freq = 60
opcache.fast_shutdown = 1
; Session(政务系统用Redis存Session)
[Session]
session.save_handler = redis
session.save_path = "tcp://redis:6379?auth=your_redis_password"
session.gc_maxlifetime = 7200
session.cookie_httponly = 1
session.cookie_secure = 0
session.use_strict_mode = 1
6.2 PHP-FPM配置
; 文件: docker/php/php-fpm.conf
[www]
user = www
group = www
; 监听方式(用socket比TCP快)
listen = /var/run/php-fpm.sock
listen.owner = www
listen.group = www
listen.mode = 0660
; 进程管理模式
; dynamic = 动态,根据负载自动增减进程数
pm = dynamic
pm.max_children = 50 ; 最多50个进程
pm.start_servers = 5 ; 启动时5个进程
pm.min_spare_servers = 5 ; 最少保持5个空闲进程
pm.max_spare_servers = 20 ; 最多保持20个空闲进程
pm.max_requests = 500 ; 每个进程处理500个请求后重启(防内存泄漏)
; 慢日志(超过3秒的请求记录下来)
slowlog = /var/www/html/storage/logs/php-fpm-slow.log
request_slowlog_timeout = 3s
; 状态页(监控用)
pm.status_path = /fpm-status
6.3 Supervisor配置(同时管理Nginx和PHP-FPM)
; 文件: docker/php/supervisord.conf
; 大白话:一个容器里同时跑Nginx和PHP-FPM,用supervisor管理
[supervisord]
nodaemon = true ; 前台运行(容器必须前台)
logfile = /dev/stdout ; 日志输出到控制台
logfile_maxbytes = 0
loglevel = info
[program:nginx]
command = nginx -g "daemon off;"
autostart = true
autorestart = true
stdout_logfile = /dev/stdout
stdout_logfile_maxbytes = 0
stderr_logfile = /dev/stderr
stderr_logfile_maxbytes = 0
[program:php-fpm]
command = php-fpm --nodaemonize
autostart = true
autorestart = true
stdout_logfile = /dev/stdout
stdout_logfile_maxbytes = 0
stderr_logfile = /dev/stderr
stderr_logfile_maxbytes = 0
6.4 Nginx配置
# 文件: docker/nginx/gov_approval.conf
server {
listen 80;
server_name _;
root /var/www/html/public;
index index.php;
# 字符集
charset utf-8;
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# 健康检查接口(K8s探针用)
location /health {
access_log off;
return 200 "OK";
add_header Content-Type text/plain;
}
# PHP-FPM状态(内部监控用,外部不能访问)
location /fpm-status {
allow 127.0.0.1;
deny all;
fastcgi_pass unix:/var/run/php-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
# 主路由
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# PHP处理
location ~ \.php$ {
fastcgi_pass unix:/var/run/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_read_timeout 300;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
}
# 附件不能直接访问(必须经过PHP鉴权)
location /storage/uploads/ {
internal;
}
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
# 禁止访问敏感文件
location ~ /\.(env|git|htaccess|DS_Store) {
deny all;
return 404;
}
}
---
七、多架构镜像构建脚本(x86 + ARM一次搞定)
#!/bin/bash
# 文件: deploy/scripts/build.sh
# 大白话:这个脚本一次构建出同时支持x86和ARM的镜像
set -e # 任何命令失败就停止
# ============================================================
# 配置区(根据实际情况修改)
# ============================================================
REGISTRY="harbor.gov-internal.cn" # Harbor仓库地址
PROJECT="gov-approval" # 项目名
IMAGE_NAME="php-app" # 镜像名
VERSION=$(git rev-parse --short HEAD) # 用git commit hash作版本号
LATEST_TAG="latest"
FULL_IMAGE="${REGISTRY}/${PROJECT}/${IMAGE_NAME}"
echo "============================================"
echo "构建信息:"
echo " 镜像: ${FULL_IMAGE}"
echo " 版本: ${VERSION}"
echo " 架构: linux/amd64, linux/arm64"
echo "============================================"
# ============================================================
# 第一步:登录Harbor仓库
# ============================================================
echo "[1/4] 登录Harbor镜像仓库..."
echo "${HARBOR_PASSWORD}" | docker login ${REGISTRY} \
-u "${HARBOR_USERNAME}" \
--password-stdin
# ============================================================
# 第二步:创建多架构构建器
# 大白话:Docker默认只能构建当前机器架构的镜像
# buildx是Docker的扩展功能,可以在x86机器上构建ARM镜像
# ============================================================
echo "[2/4] 初始化多架构构建器..."
# 检查是否已有构建器
if ! docker buildx inspect gov-builder > /dev/null 2>&1; then
docker buildx create \
--name gov-builder \
--driver docker-container \
--platform linux/amd64,linux/arm64 \
--use
docker buildx inspect gov-builder --bootstrap
else
docker buildx use gov-builder
fi
# ============================================================
# 第三步:构建并推送多架构镜像
# --platform 指定同时构建x86和ARM两个版本
# --push 构建完直接推送到仓库(多架构必须推送,不能只存本地)
# ============================================================
echo "[3/4] 构建多架构镜像并推送..."
docker buildx build \
--platform linux/amd64,linux/arm64 \
--file docker/php/Dockerfile \
--tag "${FULL_IMAGE}:${VERSION}" \
--tag "${FULL_IMAGE}:${LATEST_TAG}" \
--build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
--build-arg GIT_COMMIT=${VERSION} \
--push \
.
# ============================================================
# 第四步:验证镜像
# ============================================================
echo "[4/4] 验证镜像..."
docker buildx imagetools inspect "${FULL_IMAGE}:${VERSION}"
echo ""
echo "构建完成!"
echo "镜像地址: ${FULL_IMAGE}:${VERSION}"
---
八、Harbor私有镜像仓库搭建
#!/bin/bash
# 文件: deploy/scripts/install_harbor.sh
# 大白话:在内网服务器上装Harbor,作为私有镜像仓库
# ============================================================
# 前提:服务器已安装Docker和Docker Compose
# ============================================================
HARBOR_VERSION="v2.10.0"
HARBOR_HOSTNAME="harbor.gov-internal.cn"
HARBOR_ADMIN_PASSWORD="Harbor12345"
HARBOR_DATA_DIR="/data/harbor"
# 下载Harbor安装包(离线包,适合内网环境)
# 在有网络的机器上下载后传入内网
wget
https://github.com/goharbor/harbor/releases/download/${HARBOR_VERSION}/harbor-offline-installer-${HARBOR_VERSION}.tgz
tar -xzf harbor-offline-installer-${HARBOR_VERSION}.tgz
cd harbor
# 复制配置模板
cp harbor.yml.tmpl harbor.yml
# 修改配置
sed -i "s/hostname: reg.mydomain.com/hostname: ${HARBOR_HOSTNAME}/" harbor.yml
sed -i "s/harbor_admin_password: Harbor12345/harbor_admin_password: ${HARBOR_ADMIN_PASSWORD}/" harbor.yml
# 修改数据存储路径
sed -i "s|data_volume: /data|data_volume: ${HARBOR_DATA_DIR}|" harbor.yml
# 如果没有HTTPS证书,先禁用HTTPS(内网可以用HTTP)
# 注释掉https配置段
sed -i '/^https:/,/^[a-z]/{/^https:/d;/ port: 443/d;/ certificate:/d;/ private_key:/d}' harbor.yml
# 安装Harbor
./install.sh
echo "Harbor安装完成!"
echo "访问地址: http://${HARBOR_HOSTNAME}"
echo "管理员账号: admin"
echo "管理员密码: ${HARBOR_ADMIN_PASSWORD}"
# Harbor核心配置 harbor.yml(关键部分)
hostname: harbor.gov-internal.cn
# HTTP配置(内网用HTTP,生产建议HTTPS)
http:
port: 80
# 管理员密码
harbor_admin_password: Harbor12345
# 数据库配置
database:
password: root123
max_idle_conns: 50
max_open_conns: 100
# 数据存储路径
data_volume: /data/harbor
# 日志
log:
level: info
local:
rotate_count: 50
rotate_size: 200M
location: /var/log/harbor
---
九、本地开发环境(docker-compose)
# 文件: deploy/docker-compose.yml
# 大白话:本地开发时一键启动所有服务
version: '3.8'
services:
# PHP应用
app:
build:
context: .
dockerfile: docker/php/Dockerfile
target: production
container_name: gov_app
restart: unless-stopped
ports:
- "8080:80"
environment:
- DB_TYPE=dameng
- DB_HOST=dameng
- DB_PORT=5236
- DB_NAME=DAMENG
- DB_SCHEMA=GOV_APPROVAL
- DB_USER=SYSDBA
- DB_PASSWORD=SYSDBA001
- REDIS_HOST=redis
- REDIS_PASSWORD=redis123
- APP_ENV=production
- APP_KEY=base64:your-32-char-secret-key-here
volumes:
# 开发时挂载代码目录,改代码不用重建镜像
- ./src:/var/www/html/src
- ./public:/var/www/html/public
# 日志持久化
- ./storage/logs:/var/www/html/storage/logs
# 上传文件持久化
- ./storage/uploads:/var/www/html/storage/uploads
depends_on:
dameng:
condition: service_healthy
redis:
condition: service_healthy
networks:
- gov_network
# 达梦数据库
dameng:
image: harbor.gov-internal.cn/gov-approval/dameng:8.1.2
container_name: gov_dameng
restart: unless-stopped
ports:
- "5236:5236"
environment:
- SYSDBA_PWD=SYSDBA001
volumes:
- dameng_data:/opt/dmdbms/data
healthcheck:
test: ["CMD", "/opt/dmdbms/bin/disql", "SYSDBA/SYSDBA001@127.0.0.1:5236", "-e", "SELECT 1;"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
networks:
- gov_network
# Redis缓存
redis:
image: redis:7-alpine
container_name: gov_redis
restart: unless-stopped
command: redis-server --requirepass redis123 --maxmemory 256mb --maxmemory-policy allkeys-lru
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "-a", "redis123", "ping"]
interval: 10s
timeout: 5s
retries: 3
networks:
- gov_network
volumes:
dameng_data:
redis_data:
networks:
gov_network:
driver: bridge
---
十、Kubernetes部署文件(生产环境)
10.1 命名空间
# 文件: deploy/k8s/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: gov-approval
labels:
app: gov-approval
env: production
10.2 配置字典(非敏感配置)
# 文件: deploy/k8s/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: gov-approval-config
namespace: gov-approval
data:
DB_TYPE: "dameng"
DB_HOST: "dameng-service"
DB_PORT: "5236"
DB_NAME: "DAMENG"
DB_SCHEMA: "GOV_APPROVAL"
REDIS_HOST: "redis-service"
APP_ENV: "production"
TZ: "Asia/Shanghai"
10.3 密钥(敏感配置)
# 文件: deploy/k8s/secret.yaml
# 大白话:密码这类敏感信息单独存,base64编码(不是加密!只是编码)
# 生成方式: echo -n "SYSDBA001" | base64
apiVersion: v1
kind: Secret
metadata:
name: gov-approval-secret
namespace: gov-approval
type: Opaque
data:
DB_USER: U1lTREJB # SYSDBA
DB_PASSWORD: U1lTREJBMDAx # SYSDBA001
REDIS_PASSWORD: cmVkaXMxMjM= # redis123
APP_KEY: YmFzZTY0OnlvdXIta2V5 # 你的APP_KEY
10.4 部署配置(核心)
# 文件: deploy/k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: gov-approval-app
namespace: gov-approval
labels:
app: gov-approval
component: app
spec:
# 运行3个副本,高可用
replicas: 3
selector:
matchLabels:
app: gov-approval
component: app
# 滚动更新策略(不停机更新)
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 更新时最多多启动1个新Pod
maxUnavailable: 0 # 更新时不允许有Pod不可用(零停机)
template:
metadata:
labels:
app: gov-approval
component: app
spec:
# 镜像拉取密钥(从Harbor拉镜像需要认证)
imagePullSecrets:
- name: harbor-secret
containers:
- name: gov-approval-app
# 镜像地址(用具体版本号,不用latest,生产环境要可追溯)
image: harbor.gov-internal.cn/gov-approval/php-app:abc1234
imagePullPolicy: Always
ports:
- containerPort: 80
protocol: TCP
# 从ConfigMap和Secret注入环境变量
envFrom:
- configMapRef:
name: gov-approval-config
- secretRef:
name: gov-approval-secret
# 资源限制(防止一个Pod把整台服务器资源耗尽)
resources:
requests:
cpu: "200m" # 最少需要0.2核CPU
memory: "256Mi" # 最少需要256MB内存
limits:
cpu: "1000m" # 最多用1核CPU
memory: "512Mi" # 最多用512MB内存
# 存活探针(失败则重启容器)
livenessProbe:
httpGet:
path: /health
port: 80
initialDelaySeconds: 60 # 启动后60秒开始检查
periodSeconds: 30 # 每30秒检查一次
failureThreshold: 3 # 连续失败3次才重启
# 就绪探针(失败则从负载均衡摘除,不重启)
readinessProbe:
httpGet:
path: /health
port: 80
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 3
# 挂载持久化存储
volumeMounts:
- name: uploads-storage
mountPath: /var/www/html/storage/uploads
- name: logs-storage
mountPath: /var/www/html/storage/logs
volumes:
- name: uploads-storage
persistentVolumeClaim:
claimName: gov-approval-uploads-pvc
- name: logs-storage
persistentVolumeClaim:
claimName: gov-approval-logs-pvc
# 节点亲和性(指定部署到信创节点)
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: node-type
operator: In
values:
- xinchuang # 优先调度到打了信创标签的节点
10.5 Service(内部访问)
# 文件: deploy/k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
name: gov-approval-service
namespace: gov-approval
spec:
selector:
app: gov-approval
component: app
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP # 集群内部访问
10.6 Ingress(外部访问入口)
# 文件: deploy/k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gov-approval-ingress
namespace: gov-approval
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "300
> 继续 ed for 1m 53s
✽ Zesting… ●Z nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
nginx.ingress.kubernetes.io/proxy-connect-timeout: "60"
spec: ingressClassName: nginx
rules: - host: gov-approval.example.gov.cn
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: gov-approval-service
port:
number: 80
10.7 持久化存储
# 文件: deploy/k8s/pvc.yaml
# 大白话:申请持久化磁盘,容器重启数据不丢失
# 上传文件存储
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: gov-approval-uploads-pvc
namespace: gov-approval
spec:
accessModes:
- ReadWriteMany # 多个Pod同时读写(NFS或分布式存储)
storageClassName: nfs-storage # 用NFS存储类
resources:
requests:
storage: 100Gi
---
# 日志存储
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: gov-approval-logs-pvc
namespace: gov-approval
spec:
accessModes:
- ReadWriteMany
storageClassName: nfs-storage
resources:
requests:
storage: 20Gi
---
十一、自动化部署脚本
11.1 构建推送一体脚本
#!/bin/bash
# 文件: deploy/scripts/build_and_push.sh
# 大白话:一条命令完成:构建镜像 → 推送到Harbor → 更新K8s部署
set -e
# ============================================================
# 配置
# ============================================================
REGISTRY="harbor.gov-internal.cn"
PROJECT="gov-approval"
IMAGE_NAME="php-app"
NAMESPACE="gov-approval"
DEPLOYMENT_NAME="gov-approval-app"
# 自动获取版本号(用git commit hash)
if git rev-parse --git-dir > /dev/null 2>&1; then
VERSION=$(git rev-parse --short HEAD)
else
VERSION=$(date +%Y%m%d%H%M%S)
fi
FULL_IMAGE="${REGISTRY}/${PROJECT}/${IMAGE_NAME}:${VERSION}"
# ============================================================
# 颜色输出(让日志好看一点)
# ============================================================
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # 无颜色
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# ============================================================
# 步骤1:检查前置条件
# ============================================================
log_info "检查前置条件..."
command -v docker >/dev/null 2>&1 || { log_error "未安装docker"; exit 1; }
command -v kubectl >/dev/null 2>&1 || { log_error "未安装kubectl"; exit 1; }
if [ -z "${HARBOR_USERNAME}" ] || [ -z "${HARBOR_PASSWORD}" ]; then
log_error "请设置环境变量 HARBOR_USERNAME 和 HARBOR_PASSWORD"
exit 1
fi
# ============================================================
# 步骤2:登录Harbor
# ============================================================
log_info "登录Harbor: ${REGISTRY}"
echo "${HARBOR_PASSWORD}" | docker login "${REGISTRY}" \
-u "${HARBOR_USERNAME}" --password-stdin
# ============================================================
# 步骤3:构建多架构镜像
# ============================================================
log_info "构建多架构镜像: ${FULL_IMAGE}"
# 确保buildx构建器存在
if ! docker buildx inspect gov-builder >/dev/null 2>&1; then
log_info "创建多架构构建器..."
docker buildx create \
--name gov-builder \
--driver docker-container \
--platform linux/amd64,linux/arm64 \
--use
docker buildx inspect gov-builder --bootstrap
else
docker buildx use gov-builder
fi
# 构建并推送
docker buildx build \
--platform linux/amd64,linux/arm64 \
--file docker/php/Dockerfile \
--tag "${FULL_IMAGE}" \
--tag "${REGISTRY}/${PROJECT}/${IMAGE_NAME}:latest" \
--build-arg BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
--build-arg GIT_COMMIT="${VERSION}" \
--push \
.
log_info "镜像推送成功: ${FULL_IMAGE}"
# ============================================================
# 步骤4:更新K8s部署(滚动更新,零停机)
# ============================================================
log_info "更新K8s部署..."
# 更新镜像版本
kubectl set image deployment/${DEPLOYMENT_NAME} \
gov-approval-app=${FULL_IMAGE} \
-n ${NAMESPACE}
# 等待滚动更新完成
log_info "等待滚动更新完成..."
kubectl rollout status deployment/${DEPLOYMENT_NAME} \
-n ${NAMESPACE} \
--timeout=300s
# ============================================================
# 步骤5:验证部署结果
# ============================================================
log_info "验证部署结果..."
# 查看Pod状态
kubectl get pods -n ${NAMESPACE} -l app=gov-approval
# 查看当前镜像版本
CURRENT_IMAGE=$(kubectl get deployment ${DEPLOYMENT_NAME} \
-n ${NAMESPACE} \
-o jsonpath='{.spec.template.spec.containers[0].image}')
log_info "当前运行镜像: ${CURRENT_IMAGE}"
if [ "${CURRENT_IMAGE}" = "${FULL_IMAGE}" ]; then
log_info "部署成功!版本: ${VERSION}"
else
log_error "部署验证失败,当前镜像不匹配"
exit 1
fi
11.2 回滚脚本
#!/bin/bash
# 文件: deploy/scripts/rollback.sh
# 大白话:出问题了,一键回滚到上一个版本
NAMESPACE="gov-approval"
DEPLOYMENT_NAME="gov-approval-app"
echo "当前部署历史:"
kubectl rollout history deployment/${DEPLOYMENT_NAME} -n ${NAMESPACE}
echo ""
read -p "回滚到上一版本?(y/n): " confirm
if [ "${confirm}" = "y" ]; then
kubectl rollout undo deployment/${DEPLOYMENT_NAME} -n ${NAMESPACE}
kubectl rollout status deployment/${DEPLOYMENT_NAME} -n ${NAMESPACE} --timeout=120s
echo "回滚完成!"
kubectl get pods -n ${NAMESPACE} -l app=gov-approval
else
echo "取消回滚"
fi
---
十二、Harbor镜像仓库配置(创建项目和账号)
#!/bin/bash
# 文件: deploy/scripts/setup_harbor.sh
# 大白话:用Harbor的API自动创建项目、账号、权限
HARBOR_URL="http://harbor.gov-internal.cn"
HARBOR_ADMIN="admin"
HARBOR_ADMIN_PWD="Harbor12345"
# ============================================================
# 创建项目(相当于一个命名空间)
# ============================================================
echo "创建Harbor项目: gov-approval"
curl -s -X POST \
-u "${HARBOR_ADMIN}:${HARBOR_ADMIN_PWD}" \
-H "Content-Type: application/json" \
"${HARBOR_URL}/api/v2.0/projects" \
-d '{
"project_name": "gov-approval",
"public": false,
"metadata": {
"auto_scan": "true",
"prevent_vul": "false"
}
}'
# ============================================================
# 创建机器人账号(CI/CD用,不用人工账号)
# ============================================================
echo "创建机器人账号: robot-cicd"
ROBOT_RESPONSE=$(curl -s -X POST \
-u "${HARBOR_ADMIN}:${HARBOR_ADMIN_PWD}" \
-H "Content-Type: application/json" \
"${HARBOR_URL}/api/v2.0/robots" \
-d '{
"name": "robot-cicd",
"description": "CI/CD自动化账号",
"duration": 365,
"level": "project",
"permissions": [
{
"kind": "project",
"namespace": "gov-approval",
"access": [
{"resource": "repository", "action": "push"},
{"resource": "repository", "action": "pull"},
{"resource": "tag", "action": "create"},
{"resource": "tag", "action": "delete"}
]
}
]
}')
# 提取机器人账号密码(只显示一次,要保存好)
ROBOT_NAME=$(echo $ROBOT_RESPONSE | python3 -c "import sys,json; print(json.load(sys.stdin)['name'])")
ROBOT_SECRET=$(echo $ROBOT_RESPONSE | python3 -c "import sys,json; print(json.load(sys.stdin)['secret'])")
echo "机器人账号: ${ROBOT_NAME}"
echo "机器人密码: ${ROBOT_SECRET}"
echo "请立即保存密码,只显示一次!"
# ============================================================
# 在K8s中创建Harbor拉取密钥
# ============================================================
echo "在K8s中创建镜像拉取密钥..."
kubectl create secret docker-registry harbor-secret \
--docker-server="harbor.gov-internal.cn" \
--docker-username="${ROBOT_NAME}" \
--docker-password="${ROBOT_SECRET}" \
--namespace=gov-approval \
--dry-run=client -o yaml | kubectl apply -f -
echo "Harbor配置完成!"
---
十三、离线环境镜像分发(内网无法联网时)
#!/bin/bash
# 文件: deploy/scripts/offline_distribute.sh
# 大白话:内网服务器不能上网,用这个脚本把镜像打包传进去
FULL_IMAGE="harbor.gov-internal.cn/gov-approval/php-app:abc1234"
EXPORT_FILE="gov-approval-php-app-abc1234.tar"
# ============================================================
# 在有网络的机器上:导出镜像为tar包
# ============================================================
export_image() {
echo "导出镜像为tar包..."
# 先拉取(如果本地没有)
docker pull "${FULL_IMAGE}"
# 导出
docker save -o "${EXPORT_FILE}" "${FULL_IMAGE}"
# 压缩(镜像通常几百MB,压缩后小很多)
gzip "${EXPORT_FILE}"
echo "导出完成: ${EXPORT_FILE}.gz"
echo "文件大小: $(du -sh ${EXPORT_FILE}.gz | cut -f1)"
}
# ============================================================
# 在内网服务器上:导入镜像
# ============================================================
import_image() {
local tar_file=$1
echo "导入镜像: ${tar_file}"
# 解压并导入
gunzip -c "${tar_file}" | docker load
echo "导入完成!"
docker images | grep gov-approval
}
# ============================================================
# 传输到内网服务器(用scp或U盘)
# ============================================================
transfer_to_servers() {
local tar_file="${EXPORT_FILE}.gz"
# 内网服务器列表
SERVERS=(
"192.168.1.101" # 节点1 x86
"192.168.1.102" # 节点2 x86
"192.168.1.103" # 节点3 ARM鲲鹏
)
for server in "${SERVERS[@]}"; do
echo "传输到服务器: ${server}"
scp "${tar_file}" "root@${server}:/tmp/"
echo "在 ${server} 上导入镜像..."
ssh "root@${server}" "
gunzip -c /tmp/${tar_file} | docker load
rm /tmp/${tar_file}
echo '导入完成'
"
done
echo "所有服务器镜像分发完成!"
}
# 根据参数执行不同操作
case "$1" in
export) export_image ;;
import) import_image "$2" ;;
transfer) transfer_to_servers ;;
*)
echo "用法: $0 {export|import <file>|transfer}"
echo " export: 导出镜像为tar.gz"
echo " import <file>: 导入tar.gz镜像"
echo " transfer: 分发到所有内网服务器"
;;
esac
---
十四、KubeSphere部署(国产K8s管理平台)
#!/bin/bash
# 大白话:KubeSphere是青云科技做的K8s管理平台
# 界面友好,政务系统常用,下面是安装步骤
# ============================================================
# 在麒麟OS上安装KubeSphere(单节点,用于测试)
# ============================================================
# 前提:已安装K8s(用kubeadm或k3s)
# 安装KubeSphere核心组件
kubectl apply -f https://github.com/kubesphere/ks-installer/releases/download/v3.4.1/kubesphere-installer.yaml
kubectl apply -f https://github.com/kubesphere/ks-installer/releases/download/v3.4.1/cluster-configuration.yaml
# 查看安装进度
kubectl logs -n kubesphere-system \
$(kubectl get pod -n kubesphere-system -l app=ks-install -o jsonpath='{.items[0].metadata.name}') \
-f
# 安装完成后获取访问地址
kubectl get svc/ks-console -n kubesphere-system
# KubeSphere流水线配置(Jenkinsfile格式)
# 文件: deploy/Jenkinsfile
# 大白话:在KubeSphere里配置自动化构建流水线
pipeline {
agent {
node {
label 'maven'
}
}
environment {
REGISTRY = 'harbor.gov-internal.cn'
PROJECT = 'gov-approval'
IMAGE_NAME = 'php-app'
NAMESPACE = 'gov-approval'
DEPLOYMENT = 'gov-approval-app'
HARBOR_CRED = credentials('harbor-robot-cicd')
}
stages {
stage('拉取代码') {
steps {
checkout scm
script {
env.GIT_COMMIT_SHORT = sh(
script: 'git rev-parse --short HEAD',
returnStdout: true
).trim()
env.FULL_IMAGE = "${REGISTRY}/${PROJECT}/${IMAGE_NAME}:${GIT_COMMIT_SHORT}"
}
}
}
stage('构建镜像') {
steps {
sh """
docker buildx build \
--platform linux/amd64,linux/arm64 \
--file docker/php/Dockerfile \
--tag ${FULL_IMAGE} \
--push \
.
"""
}
}
stage('部署到测试环境') {
steps {
sh """
kubectl set image deployment/${DEPLOYMENT} \
gov-approval-app=${FULL_IMAGE} \
-n ${NAMESPACE}-test
kubectl rollout status deployment/${DEPLOYMENT} \
-n ${NAMESPACE}-test --timeout=180s
"""
}
}
stage('人工审批') {
steps {
// 等待人工确认才部署生产
input message: '确认部署到生产环境?', ok: '确认部署'
}
}
stage('部署到生产环境') {
steps {
sh """
kubectl set image deployment/${DEPLOYMENT} \
gov-approval-app=${FULL_IMAGE} \
-n ${NAMESPACE}
kubectl rollout status deployment/${DEPLOYMENT} \
-n ${NAMESPACE} --timeout=300s
"""
}
}
}
post {
success {
echo "部署成功!镜像版本: ${env.GIT_COMMIT_SHORT}"
}
failure {
echo "部署失败,自动回滚..."
sh "kubectl rollout undo deployment/${DEPLOYMENT} -n ${NAMESPACE}"
}
}
}
---
十五、常见问题和解决办法
问题1:ARM服务器上拉镜像报错 "exec format error"
原因:镜像只有x86版本,ARM跑不了
解决:重新用 --platform linux/amd64,linux/arm64 构建多架构镜像
问题2:达梦驱动在ARM上加载失败
原因:驱动.so文件是x86编译的,ARM不兼容
解决:联系达梦官方要ARM版本的pdo_dm.so驱动
问题3:内网Harbor无法访问
原因:DNS没配或证书问题
解决:
# 在每台服务器的 /etc/hosts 加上
192.168.1.200 harbor.gov-internal.cn
# 如果用HTTP,Docker需要配置insecure-registry
# 编辑 /etc/docker/daemon.json
{
"insecure-registries": ["harbor.gov-internal.cn"]
}
systemctl restart docker
问题4:Pod一直处于Pending状态
原因:资源不足或节点选择器不匹配
解决:
kubectl describe pod <pod-name> -n gov-approval
# 看Events里的报错信息
问题5:镜像拉取失败 ImagePullBackOff
原因:K8s没有Harbor的认证信息
解决:
kubectl create secret docker-registry harbor-secret \
--docker-server=harbor.gov-internal.cn \
--docker-username=robot-cicd \
--docker-password=<机器人密码> \
-n gov-approval
问题6:麒麟OS上buildx不支持多架构
原因:需要QEMU模拟器
解决:
# 安装QEMU多架构支持
docker run --privileged --rm \
tonistiigi/binfmt --install all
# 验证
docker buildx ls
---
十六、整体流程总结
开发阶段
写代码 → docker-compose本地跑 → 验证功能
构建阶段
git push → 触发流水线 → buildx构建多架构镜像 → 推送Harbor
测试阶段
自动部署测试环境 → 测试验证 → 人工审批
生产部署
kubectl set image → 滚动更新(零停机)→ 健康检查验证
应急处理
出问题 → kubectl rollout undo → 30秒回滚到上一版本
核心要点三句话:
1. 用 docker buildx 一次构建同时支持 x86 和 ARM 的镜像,解决信创架构兼容问题
2. 用 Harbor 搭内网私有仓库,离线环境用 docker save/load 打包传输
3. K8s 滚动更新保证零停机,出问题 rollout undo 一键回滚
更多推荐


所有评论(0)