clouddreamai-cicd-setup 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +189 -0
- package/bin/cicd-setup.js +3 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +187 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/gitlab-client.d.ts +80 -0
- package/dist/core/gitlab-client.d.ts.map +1 -0
- package/dist/core/gitlab-client.js +252 -0
- package/dist/core/gitlab-client.js.map +1 -0
- package/dist/core/types.d.ts +152 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +6 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/variables.d.ts +50 -0
- package/dist/core/variables.d.ts.map +1 -0
- package/dist/core/variables.js +243 -0
- package/dist/core/variables.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/prompts.d.ts +47 -0
- package/dist/utils/prompts.d.ts.map +1 -0
- package/dist/utils/prompts.js +369 -0
- package/dist/utils/prompts.js.map +1 -0
- package/dist/utils/template.d.ts +50 -0
- package/dist/utils/template.d.ts.map +1 -0
- package/dist/utils/template.js +189 -0
- package/dist/utils/template.js.map +1 -0
- package/package.json +50 -0
- package/templates/gitlab-ci/nestjs.yml +167 -0
- package/templates/gitlab-ci/vue.yml +167 -0
- package/templates/scripts/deploy.sh +141 -0
- package/templates/scripts/generate-env.sh +84 -0
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "clouddreamai-cicd-setup",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CloudDreamAI GitLab CI/CD 自动配置工具 - 支持 NestJS/Vue/React 项目的一键 CI/CD 配置",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"cicd-setup": "./bin/cicd-setup.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "ts-node src/cli.ts",
|
|
13
|
+
"start": "node dist/cli.js",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"gitlab",
|
|
18
|
+
"cicd",
|
|
19
|
+
"devops",
|
|
20
|
+
"automation",
|
|
21
|
+
"nestjs",
|
|
22
|
+
"vue",
|
|
23
|
+
"react",
|
|
24
|
+
"docker"
|
|
25
|
+
],
|
|
26
|
+
"author": "CloudDreamAI",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"axios": "^1.6.0",
|
|
30
|
+
"chalk": "^4.1.2",
|
|
31
|
+
"commander": "^11.1.0",
|
|
32
|
+
"inquirer": "^8.2.6",
|
|
33
|
+
"ora": "^5.4.1"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@types/inquirer": "^8.2.10",
|
|
37
|
+
"@types/node": "^20.10.0",
|
|
38
|
+
"ts-node": "^10.9.2",
|
|
39
|
+
"typescript": "^5.3.2"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=18.0.0"
|
|
43
|
+
},
|
|
44
|
+
"files": [
|
|
45
|
+
"dist",
|
|
46
|
+
"bin",
|
|
47
|
+
"templates",
|
|
48
|
+
"README.md"
|
|
49
|
+
]
|
|
50
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# GitLab CI/CD 配置文件 - NestJS 项目
|
|
2
|
+
stages:
|
|
3
|
+
- lint
|
|
4
|
+
- build
|
|
5
|
+
- deploy
|
|
6
|
+
|
|
7
|
+
# 全局变量
|
|
8
|
+
variables:
|
|
9
|
+
DOCKER_DRIVER: overlay2
|
|
10
|
+
NODE_VERSION: "20"
|
|
11
|
+
APP_NAME: "{{APP_NAME}}"
|
|
12
|
+
GIT_STRATEGY: fetch
|
|
13
|
+
GIT_SSL_NO_VERIFY: "true"
|
|
14
|
+
DOCKER_PULL_POLICY: if-not-present
|
|
15
|
+
DOCKER_HUB_REGISTRY: "docker.io"
|
|
16
|
+
DOCKER_HUB_IMAGE: "{{DOCKER_IMAGE}}"
|
|
17
|
+
|
|
18
|
+
# 全局缓存配置
|
|
19
|
+
cache:
|
|
20
|
+
key: ${CI_COMMIT_REF_SLUG}-${CI_JOB_NAME}
|
|
21
|
+
paths:
|
|
22
|
+
- node_modules/
|
|
23
|
+
- .npm/
|
|
24
|
+
|
|
25
|
+
# 代码质量检查阶段
|
|
26
|
+
lint:
|
|
27
|
+
stage: lint
|
|
28
|
+
image:
|
|
29
|
+
name: node:20-alpine
|
|
30
|
+
pull_policy: if-not-present
|
|
31
|
+
cache:
|
|
32
|
+
key: ${CI_COMMIT_REF_SLUG}-node-modules
|
|
33
|
+
paths:
|
|
34
|
+
- node_modules/
|
|
35
|
+
- .npm/
|
|
36
|
+
policy: pull-push
|
|
37
|
+
before_script:
|
|
38
|
+
- apk add --no-cache git curl
|
|
39
|
+
- git --version
|
|
40
|
+
- echo "Setting up Git authentication..."
|
|
41
|
+
- git config --global http.sslVerify false
|
|
42
|
+
- git config --global url."https://oauth2:${GITLAB_ACCESS_TOKEN}@{{GITLAB_HOST}}".insteadOf "http://{{GITLAB_HOST}}"
|
|
43
|
+
- git config --global url."https://oauth2:${GITLAB_ACCESS_TOKEN}@{{GITLAB_HOST}}".insteadOf "https://{{GITLAB_HOST}}"
|
|
44
|
+
- npm ci --cache .npm --prefer-offline
|
|
45
|
+
script:
|
|
46
|
+
- {{LINT_COMMAND}}
|
|
47
|
+
only:
|
|
48
|
+
- merge_requests
|
|
49
|
+
- main
|
|
50
|
+
- develop
|
|
51
|
+
|
|
52
|
+
# 构建阶段
|
|
53
|
+
build:
|
|
54
|
+
stage: build
|
|
55
|
+
cache: {}
|
|
56
|
+
image:
|
|
57
|
+
name: docker:24.0.5
|
|
58
|
+
pull_policy: if-not-present
|
|
59
|
+
before_script:
|
|
60
|
+
- docker info
|
|
61
|
+
- echo "登录到Docker Hub..."
|
|
62
|
+
- echo "$DOCKER_HUB_PASSWORD" | docker login -u $DOCKER_HUB_USERNAME --password-stdin
|
|
63
|
+
script:
|
|
64
|
+
- echo "尝试拉取最新镜像作为缓存..."
|
|
65
|
+
- docker pull $DOCKER_HUB_IMAGE:latest || true
|
|
66
|
+
- echo "构建Docker镜像..."
|
|
67
|
+
- docker build --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_HUB_IMAGE:latest -t $DOCKER_HUB_IMAGE:$CI_COMMIT_SHA -t $DOCKER_HUB_IMAGE:latest .
|
|
68
|
+
- echo "推送镜像到Docker Hub..."
|
|
69
|
+
- docker push $DOCKER_HUB_IMAGE:$CI_COMMIT_SHA
|
|
70
|
+
- docker push $DOCKER_HUB_IMAGE:latest
|
|
71
|
+
only:
|
|
72
|
+
- main
|
|
73
|
+
- develop
|
|
74
|
+
|
|
75
|
+
# 开发环境部署(develop 分支自动触发)
|
|
76
|
+
deploy_dev:
|
|
77
|
+
stage: deploy
|
|
78
|
+
image:
|
|
79
|
+
name: alpine:latest
|
|
80
|
+
pull_policy: if-not-present
|
|
81
|
+
variables:
|
|
82
|
+
ENV_TYPE: "development"
|
|
83
|
+
ENV_FILE_CONTENT: $DEV_ENV_FILE
|
|
84
|
+
DEPLOY_DIR: "{{DEPLOY_DIR}}"
|
|
85
|
+
APP_PORT: "{{DEV_PORT}}"
|
|
86
|
+
cache: {}
|
|
87
|
+
before_script:
|
|
88
|
+
- apk add --no-cache openssh-client docker-compose bash openssl rsync
|
|
89
|
+
- eval $(ssh-agent -s)
|
|
90
|
+
- mkdir -p ~/.ssh
|
|
91
|
+
- chmod 700 ~/.ssh
|
|
92
|
+
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - 2>/dev/null || (echo "无法加载SSH密钥,尝试不同格式..." && echo "$SSH_PRIVATE_KEY" | base64 -d | ssh-add - 2>/dev/null || echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa && ssh-add ~/.ssh/id_rsa)
|
|
93
|
+
- ssh-keyscan $TEST_SERVER_HOST >> ~/.ssh/known_hosts
|
|
94
|
+
- chmod 644 ~/.ssh/known_hosts
|
|
95
|
+
script:
|
|
96
|
+
- ssh root@$TEST_SERVER_HOST "mkdir -p $DEPLOY_DIR"
|
|
97
|
+
- ssh root@$TEST_SERVER_HOST "which rsync || apk add --no-cache rsync"
|
|
98
|
+
- rsync -avz --delete --exclude='.git/' --exclude='node_modules/' . root@$TEST_SERVER_HOST:$DEPLOY_DIR/
|
|
99
|
+
- ssh root@$TEST_SERVER_HOST "export DOCKER_HUB_USERNAME='$DOCKER_HUB_USERNAME' && export DOCKER_HUB_PASSWORD='$DOCKER_HUB_PASSWORD' && export APP_PORT='$APP_PORT' && cd $DEPLOY_DIR && chmod +x ci/deploy.sh && bash ci/deploy.sh $ENV_TYPE"
|
|
100
|
+
- ssh root@$TEST_SERVER_HOST "sleep 30 && curl -f http://localhost:$APP_PORT/api || exit 1"
|
|
101
|
+
environment:
|
|
102
|
+
name: development
|
|
103
|
+
url: {{DEV_URL}}
|
|
104
|
+
only:
|
|
105
|
+
- develop
|
|
106
|
+
|
|
107
|
+
# 生产环境部署(main 分支手动触发)
|
|
108
|
+
deploy_prod:
|
|
109
|
+
stage: deploy
|
|
110
|
+
image:
|
|
111
|
+
name: alpine:latest
|
|
112
|
+
pull_policy: if-not-present
|
|
113
|
+
variables:
|
|
114
|
+
ENV_TYPE: "production"
|
|
115
|
+
ENV_FILE_CONTENT: $PROD_ENV_FILE
|
|
116
|
+
DEPLOY_DIR: "{{DEPLOY_DIR}}"
|
|
117
|
+
APP_PORT: "{{PROD_PORT}}"
|
|
118
|
+
cache: {}
|
|
119
|
+
before_script:
|
|
120
|
+
- apk add --no-cache openssh-client docker-compose bash openssl rsync
|
|
121
|
+
- eval $(ssh-agent -s)
|
|
122
|
+
- mkdir -p ~/.ssh
|
|
123
|
+
- chmod 700 ~/.ssh
|
|
124
|
+
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - 2>/dev/null || (echo "无法加载SSH密钥,尝试不同格式..." && echo "$SSH_PRIVATE_KEY" | base64 -d | ssh-add - 2>/dev/null || echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa && ssh-add ~/.ssh/id_rsa)
|
|
125
|
+
- ssh-keyscan $PROD_SERVER_HOST >> ~/.ssh/known_hosts
|
|
126
|
+
- chmod 644 ~/.ssh/known_hosts
|
|
127
|
+
script:
|
|
128
|
+
- ssh root@$PROD_SERVER_HOST "mkdir -p $DEPLOY_DIR"
|
|
129
|
+
- ssh root@$PROD_SERVER_HOST "which rsync || apk add --no-cache rsync"
|
|
130
|
+
- rsync -avz --delete --exclude='.git/' --exclude='node_modules/' . root@$PROD_SERVER_HOST:$DEPLOY_DIR/
|
|
131
|
+
- ssh root@$PROD_SERVER_HOST "export DOCKER_HUB_USERNAME='$DOCKER_HUB_USERNAME' && export DOCKER_HUB_PASSWORD='$DOCKER_HUB_PASSWORD' && export APP_PORT='$APP_PORT' && cd $DEPLOY_DIR && chmod +x ci/deploy.sh && bash ci/deploy.sh $ENV_TYPE"
|
|
132
|
+
- ssh root@$PROD_SERVER_HOST "sleep 30 && curl -f http://localhost:$APP_PORT/api || exit 1"
|
|
133
|
+
environment:
|
|
134
|
+
name: production
|
|
135
|
+
url: {{PROD_URL}}
|
|
136
|
+
only:
|
|
137
|
+
- main
|
|
138
|
+
when: manual
|
|
139
|
+
|
|
140
|
+
# 回滚部署(可选)
|
|
141
|
+
rollback:
|
|
142
|
+
stage: deploy
|
|
143
|
+
image:
|
|
144
|
+
name: alpine:latest
|
|
145
|
+
pull_policy: if-not-present
|
|
146
|
+
variables:
|
|
147
|
+
DEPLOY_DIR: "{{DEPLOY_DIR}}"
|
|
148
|
+
APP_PORT: "{{PROD_PORT}}"
|
|
149
|
+
cache: {}
|
|
150
|
+
before_script:
|
|
151
|
+
- apk add --no-cache openssh-client openssl
|
|
152
|
+
- eval $(ssh-agent -s)
|
|
153
|
+
- mkdir -p ~/.ssh
|
|
154
|
+
- chmod 700 ~/.ssh
|
|
155
|
+
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - 2>/dev/null || (echo "无法加载SSH密钥,尝试不同格式..." && echo "$SSH_PRIVATE_KEY" | base64 -d | ssh-add - 2>/dev/null || echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa && ssh-add ~/.ssh/id_rsa)
|
|
156
|
+
- ssh-keyscan $PROD_SERVER_HOST >> ~/.ssh/known_hosts
|
|
157
|
+
- chmod 644 ~/.ssh/known_hosts
|
|
158
|
+
script:
|
|
159
|
+
- ssh root@$PROD_SERVER_HOST "cd $DEPLOY_DIR && export APP_PORT=$APP_PORT && docker-compose down"
|
|
160
|
+
- ssh root@$PROD_SERVER_HOST "cd $DEPLOY_DIR && export APP_PORT=$APP_PORT && docker-compose pull"
|
|
161
|
+
- ssh root@$PROD_SERVER_HOST "cd $DEPLOY_DIR && export APP_PORT=$APP_PORT && docker-compose up -d"
|
|
162
|
+
environment:
|
|
163
|
+
name: production
|
|
164
|
+
url: {{PROD_URL}}
|
|
165
|
+
when: manual
|
|
166
|
+
only:
|
|
167
|
+
- main
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# GitLab CI/CD 配置文件 - Vue 项目
|
|
2
|
+
stages:
|
|
3
|
+
- lint
|
|
4
|
+
- build
|
|
5
|
+
- deploy
|
|
6
|
+
|
|
7
|
+
# 全局变量
|
|
8
|
+
variables:
|
|
9
|
+
DOCKER_DRIVER: overlay2
|
|
10
|
+
NODE_VERSION: "20"
|
|
11
|
+
APP_NAME: "{{APP_NAME}}"
|
|
12
|
+
GIT_STRATEGY: fetch
|
|
13
|
+
GIT_SSL_NO_VERIFY: "true"
|
|
14
|
+
DOCKER_PULL_POLICY: if-not-present
|
|
15
|
+
DOCKER_HUB_REGISTRY: "docker.io"
|
|
16
|
+
DOCKER_HUB_IMAGE: "{{DOCKER_IMAGE}}"
|
|
17
|
+
|
|
18
|
+
# 全局缓存配置
|
|
19
|
+
cache:
|
|
20
|
+
key: ${CI_COMMIT_REF_SLUG}-${CI_JOB_NAME}
|
|
21
|
+
paths:
|
|
22
|
+
- node_modules/
|
|
23
|
+
- .npm/
|
|
24
|
+
|
|
25
|
+
# 代码质量检查阶段
|
|
26
|
+
lint:
|
|
27
|
+
stage: lint
|
|
28
|
+
image:
|
|
29
|
+
name: node:20-alpine
|
|
30
|
+
pull_policy: if-not-present
|
|
31
|
+
cache:
|
|
32
|
+
key: ${CI_COMMIT_REF_SLUG}-node-modules
|
|
33
|
+
paths:
|
|
34
|
+
- node_modules/
|
|
35
|
+
- .npm/
|
|
36
|
+
policy: pull-push
|
|
37
|
+
before_script:
|
|
38
|
+
- apk add --no-cache git curl
|
|
39
|
+
- git --version
|
|
40
|
+
- echo "Setting up Git authentication..."
|
|
41
|
+
- git config --global http.sslVerify false
|
|
42
|
+
- git config --global url."https://oauth2:${GITLAB_ACCESS_TOKEN}@{{GITLAB_HOST}}".insteadOf "http://{{GITLAB_HOST}}"
|
|
43
|
+
- git config --global url."https://oauth2:${GITLAB_ACCESS_TOKEN}@{{GITLAB_HOST}}".insteadOf "https://{{GITLAB_HOST}}"
|
|
44
|
+
- npm ci --cache .npm --prefer-offline
|
|
45
|
+
script:
|
|
46
|
+
- {{LINT_COMMAND}}
|
|
47
|
+
only:
|
|
48
|
+
- merge_requests
|
|
49
|
+
- main
|
|
50
|
+
- develop
|
|
51
|
+
|
|
52
|
+
# 构建阶段
|
|
53
|
+
build:
|
|
54
|
+
stage: build
|
|
55
|
+
cache: {}
|
|
56
|
+
image:
|
|
57
|
+
name: docker:24.0.5
|
|
58
|
+
pull_policy: if-not-present
|
|
59
|
+
before_script:
|
|
60
|
+
- docker info
|
|
61
|
+
- echo "登录到Docker Hub..."
|
|
62
|
+
- echo "$DOCKER_HUB_PASSWORD" | docker login -u $DOCKER_HUB_USERNAME --password-stdin
|
|
63
|
+
script:
|
|
64
|
+
- echo "尝试拉取最新镜像作为缓存..."
|
|
65
|
+
- docker pull $DOCKER_HUB_IMAGE:latest || true
|
|
66
|
+
- echo "构建Docker镜像..."
|
|
67
|
+
- docker build --build-arg BUILDKIT_INLINE_CACHE=1 --cache-from $DOCKER_HUB_IMAGE:latest -t $DOCKER_HUB_IMAGE:$CI_COMMIT_SHA -t $DOCKER_HUB_IMAGE:latest .
|
|
68
|
+
- echo "推送镜像到Docker Hub..."
|
|
69
|
+
- docker push $DOCKER_HUB_IMAGE:$CI_COMMIT_SHA
|
|
70
|
+
- docker push $DOCKER_HUB_IMAGE:latest
|
|
71
|
+
only:
|
|
72
|
+
- main
|
|
73
|
+
- develop
|
|
74
|
+
|
|
75
|
+
# 开发环境部署(develop 分支自动触发)
|
|
76
|
+
deploy_dev:
|
|
77
|
+
stage: deploy
|
|
78
|
+
image:
|
|
79
|
+
name: alpine:latest
|
|
80
|
+
pull_policy: if-not-present
|
|
81
|
+
variables:
|
|
82
|
+
ENV_TYPE: "development"
|
|
83
|
+
ENV_FILE_CONTENT: $DEV_ENV_FILE
|
|
84
|
+
DEPLOY_DIR: "{{DEPLOY_DIR}}"
|
|
85
|
+
APP_PORT: "{{DEV_PORT}}"
|
|
86
|
+
cache: {}
|
|
87
|
+
before_script:
|
|
88
|
+
- apk add --no-cache openssh-client docker-compose bash openssl rsync
|
|
89
|
+
- eval $(ssh-agent -s)
|
|
90
|
+
- mkdir -p ~/.ssh
|
|
91
|
+
- chmod 700 ~/.ssh
|
|
92
|
+
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - 2>/dev/null || (echo "无法加载SSH密钥,尝试不同格式..." && echo "$SSH_PRIVATE_KEY" | base64 -d | ssh-add - 2>/dev/null || echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa && ssh-add ~/.ssh/id_rsa)
|
|
93
|
+
- ssh-keyscan $TEST_SERVER_HOST >> ~/.ssh/known_hosts
|
|
94
|
+
- chmod 644 ~/.ssh/known_hosts
|
|
95
|
+
script:
|
|
96
|
+
- ssh root@$TEST_SERVER_HOST "mkdir -p $DEPLOY_DIR"
|
|
97
|
+
- ssh root@$TEST_SERVER_HOST "which rsync || apk add --no-cache rsync"
|
|
98
|
+
- rsync -avz --delete --exclude='.git/' --exclude='node_modules/' . root@$TEST_SERVER_HOST:$DEPLOY_DIR/
|
|
99
|
+
- ssh root@$TEST_SERVER_HOST "export DOCKER_HUB_USERNAME='$DOCKER_HUB_USERNAME' && export DOCKER_HUB_PASSWORD='$DOCKER_HUB_PASSWORD' && export APP_PORT='$APP_PORT' && cd $DEPLOY_DIR && chmod +x ci/deploy.sh && bash ci/deploy.sh $ENV_TYPE"
|
|
100
|
+
- ssh root@$TEST_SERVER_HOST "sleep 30 && curl -f http://localhost:$APP_PORT/ || exit 1"
|
|
101
|
+
environment:
|
|
102
|
+
name: development
|
|
103
|
+
url: {{DEV_URL}}
|
|
104
|
+
only:
|
|
105
|
+
- develop
|
|
106
|
+
|
|
107
|
+
# 生产环境部署(main 分支手动触发)
|
|
108
|
+
deploy_prod:
|
|
109
|
+
stage: deploy
|
|
110
|
+
image:
|
|
111
|
+
name: alpine:latest
|
|
112
|
+
pull_policy: if-not-present
|
|
113
|
+
variables:
|
|
114
|
+
ENV_TYPE: "production"
|
|
115
|
+
ENV_FILE_CONTENT: $PROD_ENV_FILE
|
|
116
|
+
DEPLOY_DIR: "{{DEPLOY_DIR}}"
|
|
117
|
+
APP_PORT: "{{PROD_PORT}}"
|
|
118
|
+
cache: {}
|
|
119
|
+
before_script:
|
|
120
|
+
- apk add --no-cache openssh-client docker-compose bash openssl rsync
|
|
121
|
+
- eval $(ssh-agent -s)
|
|
122
|
+
- mkdir -p ~/.ssh
|
|
123
|
+
- chmod 700 ~/.ssh
|
|
124
|
+
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - 2>/dev/null || (echo "无法加载SSH密钥,尝试不同格式..." && echo "$SSH_PRIVATE_KEY" | base64 -d | ssh-add - 2>/dev/null || echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa && ssh-add ~/.ssh/id_rsa)
|
|
125
|
+
- ssh-keyscan $PROD_SERVER_HOST >> ~/.ssh/known_hosts
|
|
126
|
+
- chmod 644 ~/.ssh/known_hosts
|
|
127
|
+
script:
|
|
128
|
+
- ssh root@$PROD_SERVER_HOST "mkdir -p $DEPLOY_DIR"
|
|
129
|
+
- ssh root@$PROD_SERVER_HOST "which rsync || apk add --no-cache rsync"
|
|
130
|
+
- rsync -avz --delete --exclude='.git/' --exclude='node_modules/' . root@$PROD_SERVER_HOST:$DEPLOY_DIR/
|
|
131
|
+
- ssh root@$PROD_SERVER_HOST "export DOCKER_HUB_USERNAME='$DOCKER_HUB_USERNAME' && export DOCKER_HUB_PASSWORD='$DOCKER_HUB_PASSWORD' && export APP_PORT='$APP_PORT' && cd $DEPLOY_DIR && chmod +x ci/deploy.sh && bash ci/deploy.sh $ENV_TYPE"
|
|
132
|
+
- ssh root@$PROD_SERVER_HOST "sleep 30 && curl -f http://localhost:$APP_PORT/ || exit 1"
|
|
133
|
+
environment:
|
|
134
|
+
name: production
|
|
135
|
+
url: {{PROD_URL}}
|
|
136
|
+
only:
|
|
137
|
+
- main
|
|
138
|
+
when: manual
|
|
139
|
+
|
|
140
|
+
# 回滚部署(可选)
|
|
141
|
+
rollback:
|
|
142
|
+
stage: deploy
|
|
143
|
+
image:
|
|
144
|
+
name: alpine:latest
|
|
145
|
+
pull_policy: if-not-present
|
|
146
|
+
variables:
|
|
147
|
+
DEPLOY_DIR: "{{DEPLOY_DIR}}"
|
|
148
|
+
APP_PORT: "{{PROD_PORT}}"
|
|
149
|
+
cache: {}
|
|
150
|
+
before_script:
|
|
151
|
+
- apk add --no-cache openssh-client openssl
|
|
152
|
+
- eval $(ssh-agent -s)
|
|
153
|
+
- mkdir -p ~/.ssh
|
|
154
|
+
- chmod 700 ~/.ssh
|
|
155
|
+
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add - 2>/dev/null || (echo "无法加载SSH密钥,尝试不同格式..." && echo "$SSH_PRIVATE_KEY" | base64 -d | ssh-add - 2>/dev/null || echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa && ssh-add ~/.ssh/id_rsa)
|
|
156
|
+
- ssh-keyscan $PROD_SERVER_HOST >> ~/.ssh/known_hosts
|
|
157
|
+
- chmod 644 ~/.ssh/known_hosts
|
|
158
|
+
script:
|
|
159
|
+
- ssh root@$PROD_SERVER_HOST "cd $DEPLOY_DIR && export APP_PORT=$APP_PORT && docker-compose down"
|
|
160
|
+
- ssh root@$PROD_SERVER_HOST "cd $DEPLOY_DIR && export APP_PORT=$APP_PORT && docker-compose pull"
|
|
161
|
+
- ssh root@$PROD_SERVER_HOST "cd $DEPLOY_DIR && export APP_PORT=$APP_PORT && docker-compose up -d"
|
|
162
|
+
environment:
|
|
163
|
+
name: production
|
|
164
|
+
url: {{PROD_URL}}
|
|
165
|
+
when: manual
|
|
166
|
+
only:
|
|
167
|
+
- main
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# 部署脚本 - 由CI/CD自动调用
|
|
4
|
+
# 此脚本不需要手动执行
|
|
5
|
+
|
|
6
|
+
set -e
|
|
7
|
+
|
|
8
|
+
# 环境变量
|
|
9
|
+
APP_NAME="{{APP_NAME}}"
|
|
10
|
+
DEPLOY_PATH="{{DEPLOY_DIR}}"
|
|
11
|
+
ENV_TYPE=${1:-development}
|
|
12
|
+
|
|
13
|
+
# 根据环境设置端口
|
|
14
|
+
if [ "$ENV_TYPE" = "production" ]; then
|
|
15
|
+
export APP_PORT={{PROD_PORT}}
|
|
16
|
+
else
|
|
17
|
+
export APP_PORT={{DEV_PORT}}
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
echo "开始部署 $APP_NAME 到 $ENV_TYPE 环境 (端口: $APP_PORT)..."
|
|
21
|
+
|
|
22
|
+
# 确保目录存在
|
|
23
|
+
mkdir -p $DEPLOY_PATH
|
|
24
|
+
|
|
25
|
+
# 当在CI/CD中执行时,文件已经通过rsync复制到部署目录,无需再次复制
|
|
26
|
+
if [ "$PWD" != "$DEPLOY_PATH" ]; then
|
|
27
|
+
echo "复制项目文件到部署目录..."
|
|
28
|
+
cp -r . $DEPLOY_PATH/
|
|
29
|
+
cd $DEPLOY_PATH
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
# 生成环境变量文件
|
|
33
|
+
echo "生成环境变量文件..."
|
|
34
|
+
bash ci/generate-env.sh $ENV_TYPE
|
|
35
|
+
|
|
36
|
+
# 检查Docker是否已安装
|
|
37
|
+
if ! command -v docker &> /dev/null; then
|
|
38
|
+
echo "Docker未安装,尝试安装Docker..."
|
|
39
|
+
if command -v apt-get &> /dev/null; then
|
|
40
|
+
apt-get update
|
|
41
|
+
apt-get install -y apt-transport-https ca-certificates curl software-properties-common
|
|
42
|
+
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
|
|
43
|
+
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
|
|
44
|
+
apt-get update
|
|
45
|
+
apt-get install -y docker-ce
|
|
46
|
+
elif command -v yum &> /dev/null; then
|
|
47
|
+
yum install -y yum-utils
|
|
48
|
+
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
|
|
49
|
+
yum install -y docker-ce docker-ce-cli containerd.io
|
|
50
|
+
systemctl start docker
|
|
51
|
+
systemctl enable docker
|
|
52
|
+
elif command -v apk &> /dev/null; then
|
|
53
|
+
apk add --update docker
|
|
54
|
+
service docker start
|
|
55
|
+
else
|
|
56
|
+
echo "无法确定包管理器,请手动安装Docker"
|
|
57
|
+
exit 1
|
|
58
|
+
fi
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# 检查并安装 docker-compose
|
|
62
|
+
if ! command -v docker-compose &> /dev/null; then
|
|
63
|
+
echo "安装 docker-compose..."
|
|
64
|
+
|
|
65
|
+
if ! command -v curl &> /dev/null; then
|
|
66
|
+
echo "安装curl..."
|
|
67
|
+
if command -v apt-get &> /dev/null; then
|
|
68
|
+
apt-get update && apt-get install -y curl
|
|
69
|
+
elif command -v yum &> /dev/null; then
|
|
70
|
+
yum install -y curl
|
|
71
|
+
elif command -v apk &> /dev/null; then
|
|
72
|
+
apk add --no-cache curl
|
|
73
|
+
fi
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
if command -v apt-get &> /dev/null; then
|
|
77
|
+
apt-get update && apt-get install -y docker-compose
|
|
78
|
+
elif command -v yum &> /dev/null; then
|
|
79
|
+
yum install -y docker-compose
|
|
80
|
+
elif command -v apk &> /dev/null; then
|
|
81
|
+
apk add --no-cache docker-compose
|
|
82
|
+
else
|
|
83
|
+
echo "无法确定包管理器,尝试使用pip安装..."
|
|
84
|
+
pip install docker-compose || pip3 install docker-compose
|
|
85
|
+
fi
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# 再次检查 docker-compose 是否已安装
|
|
89
|
+
if ! command -v docker-compose &> /dev/null; then
|
|
90
|
+
echo "无法安装 docker-compose,尝试手动安装最新版本..."
|
|
91
|
+
COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep 'tag_name' | cut -d\" -f4)
|
|
92
|
+
curl -L "https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
|
93
|
+
chmod +x /usr/local/bin/docker-compose
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
# 拉取最新镜像并启动Docker容器
|
|
97
|
+
echo "拉取最新镜像并启动Docker容器..."
|
|
98
|
+
|
|
99
|
+
# 登录Docker Hub(如果设置了凭据)
|
|
100
|
+
if [ -n "$DOCKER_HUB_USERNAME" ] && [ -n "$DOCKER_HUB_PASSWORD" ]; then
|
|
101
|
+
echo "登录Docker Hub..."
|
|
102
|
+
echo "$DOCKER_HUB_PASSWORD" | docker login -u "$DOCKER_HUB_USERNAME" --password-stdin
|
|
103
|
+
else
|
|
104
|
+
echo "未设置Docker Hub凭据,尝试匿名拉取镜像..."
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
# 停止并移除旧容器
|
|
108
|
+
echo "清理现有容器..."
|
|
109
|
+
docker-compose down --remove-orphans || true
|
|
110
|
+
docker container ls -a | grep '$APP_NAME' | awk '{print $1}' | xargs -r docker container rm -f
|
|
111
|
+
|
|
112
|
+
# 尝试拉取镜像
|
|
113
|
+
echo "尝试拉取Docker Hub镜像..."
|
|
114
|
+
if docker-compose pull; then
|
|
115
|
+
echo "镜像拉取成功,启动容器..."
|
|
116
|
+
APP_PORT=$APP_PORT docker-compose up -d
|
|
117
|
+
else
|
|
118
|
+
echo "无法从Docker Hub拉取镜像,检查是否存在Dockerfile进行本地构建..."
|
|
119
|
+
if [ -f "Dockerfile" ]; then
|
|
120
|
+
echo "找到Dockerfile,进行本地构建..."
|
|
121
|
+
export DOCKER_IMAGE="$APP_NAME:local"
|
|
122
|
+
docker build -t $DOCKER_IMAGE .
|
|
123
|
+
APP_PORT=$APP_PORT docker-compose up -d
|
|
124
|
+
else
|
|
125
|
+
echo "错误:无法拉取镜像且未找到Dockerfile,部署失败"
|
|
126
|
+
exit 1
|
|
127
|
+
fi
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# 检查部署状态
|
|
131
|
+
echo "检查部署状态..."
|
|
132
|
+
sleep 10
|
|
133
|
+
if docker-compose ps | grep -q "$APP_NAME.*Up"; then
|
|
134
|
+
echo "部署成功! $APP_NAME 服务已启动"
|
|
135
|
+
else
|
|
136
|
+
echo "部署失败! 请检查日志"
|
|
137
|
+
docker-compose logs
|
|
138
|
+
exit 1
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
echo "部署完成!"
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# 环境变量生成脚本
|
|
4
|
+
# 用法: bash generate-env.sh [environment]
|
|
5
|
+
# 示例: bash generate-env.sh production
|
|
6
|
+
|
|
7
|
+
ENV_TYPE=${1:-development}
|
|
8
|
+
ENV_FILE=".env"
|
|
9
|
+
|
|
10
|
+
echo "正在生成 $ENV_TYPE 环境的环境变量文件..."
|
|
11
|
+
|
|
12
|
+
# 检查是否在CI环境中运行
|
|
13
|
+
if [ -n "$CI_ENVIRONMENT_NAME" ]; then
|
|
14
|
+
echo "在CI/CD环境中运行,使用CI/CD变量..."
|
|
15
|
+
|
|
16
|
+
# 检查是否有文件类型的环境变量
|
|
17
|
+
if [ -n "$ENV_FILE_CONTENT" ]; then
|
|
18
|
+
echo "检测到ENV_FILE_CONTENT变量,直接使用文件内容..."
|
|
19
|
+
echo "$ENV_FILE_CONTENT" > $ENV_FILE
|
|
20
|
+
echo "环境变量文件已生成: $ENV_FILE"
|
|
21
|
+
exit 0
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
# 如果没有文件类型变量,则从单独的CI/CD变量构建
|
|
25
|
+
echo "# 由CI/CD自动生成的环境变量文件 - $(date)" > $ENV_FILE
|
|
26
|
+
|
|
27
|
+
# 读取.env.example作为模板
|
|
28
|
+
if [ -f ".env.example" ]; then
|
|
29
|
+
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
30
|
+
# 跳过注释和空行
|
|
31
|
+
if [[ $line =~ ^#.*$ ]] || [[ -z $line ]]; then
|
|
32
|
+
echo "$line" >> $ENV_FILE
|
|
33
|
+
continue
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# 提取变量名
|
|
37
|
+
VAR_NAME=$(echo "$line" | cut -d= -f1)
|
|
38
|
+
|
|
39
|
+
# 检查CI/CD变量中是否存在该变量
|
|
40
|
+
VAR_VALUE=$(env | grep "^$VAR_NAME=" | cut -d= -f2-)
|
|
41
|
+
|
|
42
|
+
if [ -n "$VAR_VALUE" ]; then
|
|
43
|
+
echo "$VAR_NAME=$VAR_VALUE" >> $ENV_FILE
|
|
44
|
+
else
|
|
45
|
+
# 如果在CI/CD变量中找不到,保留原样
|
|
46
|
+
echo "$line" >> $ENV_FILE
|
|
47
|
+
fi
|
|
48
|
+
done < .env.example
|
|
49
|
+
else
|
|
50
|
+
echo "警告: 未找到 .env.example 文件,将创建一个基本的环境变量文件"
|
|
51
|
+
cat << EOF > $ENV_FILE
|
|
52
|
+
# 由CI/CD自动生成的基本环境变量文件 - $(date)
|
|
53
|
+
# 应用配置
|
|
54
|
+
NODE_ENV=$ENV_TYPE
|
|
55
|
+
PORT={{APP_PORT}}
|
|
56
|
+
EOF
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
else
|
|
60
|
+
# 本地开发环境
|
|
61
|
+
echo "在本地环境中运行,请确保已经创建了.env文件"
|
|
62
|
+
|
|
63
|
+
if [ ! -f "$ENV_FILE" ]; then
|
|
64
|
+
echo "警告: $ENV_FILE 文件不存在,将从 .env.example 创建一个副本"
|
|
65
|
+
|
|
66
|
+
if [ -f ".env.example" ]; then
|
|
67
|
+
cp .env.example $ENV_FILE
|
|
68
|
+
else
|
|
69
|
+
echo "未找到 .env.example,创建基本环境变量文件"
|
|
70
|
+
cat << EOF > $ENV_FILE
|
|
71
|
+
# 本地开发环境变量配置 - $(date)
|
|
72
|
+
# 应用配置
|
|
73
|
+
NODE_ENV=development
|
|
74
|
+
PORT=3000
|
|
75
|
+
EOF
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
echo "请编辑 $ENV_FILE 文件并填写必要的环境变量值"
|
|
79
|
+
else
|
|
80
|
+
echo "已检测到 $ENV_FILE 文件,将使用现有文件"
|
|
81
|
+
fi
|
|
82
|
+
fi
|
|
83
|
+
|
|
84
|
+
echo "环境变量配置完成!"
|