The Scripts Of Docker Swarm Operator

docker-swarm 部署流程:

  • 基于前一篇,每当在jenkins构建完之后,都会生成与对应项目分支相关的镜像(线上也如此配置,区别在于若线上环境则仅发布,开发/测试环境则发布与部署)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 脚本框架
CGManage
├── bin
│   └── botstudio.sh
├── config
│   ├── botstudio_config
│   ├── common_bot_config
│   ├── docker-compose-swarm.yml
│   └── swarm.env
└── modules
   ├── Help
   ├── swarm_release
   ├── swarm_rollback
   ├── swarm_start
   ├── swarm_status
   └── swarm_stop
   └── swarm_exec
  • 需求分析
需求 配置文件及描述
config文件夹 botstudio_config中进行定义统一的服务数量配置以及服务内相关参数的配置,swarm.env为镜像环境模板,docker-compose-swarm.yml为docker swarm启动模版
swarm_start 使用docker service scale 对应workspaceName=Num 或者 docker service update –replicas Num 对应workspaceName 进行服务启动
swarm_stop 使用docker service scale 对应workspaceName=0 或者docker service update –replicas 0 对应workspaceName 进行服务关闭
swarm_release 基于config内容进行具体服务配置的适配,然后,使用docker stack -c docker-compose.yml 进行 对应workspaceName服务的部署;配置不变更,docker service update –image imageName 对应workspaceName服务的镜像变更操作
swarm_status 使用docker service ps 对应workspaceName查询相应的服务状态
swarm_rollback 基于docker swarm只能存储上一次操作(上一次操作可以update镜像,服务副本的增缩容等相关配置)而进行操作回滚(具有一定的随机性,除非记录上一次有实质性结果的操作行为)
swarm_exec 基于docker api能直接以某种终端格式(bash,sh,基于容器的支持)进入对于的task(容器),方便进行调试
命令参考
1
2
3
4
5
6
7
8
botstudio.sh --deploy -p"密码"  # 如果已有服务则直接平滑更新应用,不停服;如无服务,则直接部署并启动服务
botstudio.sh --deploy [--start] -p"密码" # 如果已有服务,则先停服,更新应用,再决定是否通过start起服(与上述相比,是闪断还是停服更新)
botstudio.sh status [workspaceNum] # 查看全部或特定的服务状态
botstudio.sh start [workspaceNum] # 启动全部或特定的服务
botstudio.sh stop [workspaceNum] # 暂停全部或特定的服务
botstudio.sh restart [workspaceNum] # 重启全部或特定的服务
botstudio.sh exec [workspaceNum] # 进入特定的服务,不指定则直接退出
botstudio.sh --rollback [-t time_stamp] [--start] -p"密码" # 如果配置-t,则回滚特定的time_stamp,如无,则回滚上一次,但本次配置仍旧保留,同时,支持是否闪断或者停服回滚
  • 效果展示
Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
FROM 基础镜像(python)
WORKDIR /工作目录
COPY ./requirements.txt .
ENV TZ=PRC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# RUN apk update && apk add --no-cache curl
RUN 初始化相关的环境依赖
COPY/ADD 业务代码 # 区别在于是目录还是包
# ENTRYPOINT只在启动的时候才会执行,分别在容器被调度到其他节点,容器故障重启的时候,节点信息可能变动才需要更新一下关于宿主机的配置信息
#ENTRYPOINT ["/bin/bash", "-c", "curl --unix-socket /var/run/docker.sock http://localhost/info > ./HostMessage.log && exec python ${START_UP_PY_PATH}"]
CMD ["/bin/bash", "-c", "python ${START_UP_PY_PATH}"]
# 面试考察点:ENTRYPOINT和CMD都可以被--entrypoint以及run后面跟随的命令所覆盖,只是ENTRYPOINT的优先级比CMD的高
botstudio_config
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#!/bin/bash
#config for battleserver
#declare -A workspace1BattleServer
#declare -A workspace2BattleServer

BotstudioWorkspace="workspace1..2..3..4..11"

# 进行业务内参数定义
for WORKSPACE in ${BotstudioWorkspace}
do
case "${WORKSPACE}" in
workspace1)
declare -A workspace1Botstudio
#workspace1
#一个admin节点
workspace1Botstudio=(
[key]='value'
)
;;
workspace2)
declare -A workspace2Botstudio
#workspace2
#admin集群-admin1
workspace2Botstudio=(
[key]='value'
)
;;
workspace3)
declare -A workspace3Botstudio
#workspace3
#admin集群-admin2
workspace3Botstudio=(
[key]='value'
)
;;
workspace4)
declare -A workspace4Botstudio
#workspace4
#admin集群-admin3
workspace4Botstudio=(
[key]='value'
)
;;
workspace11)
declare -A workspace11Botstudio
#workspace11
#executor-01
workspace11Botstudio=(
[key]='value'
)
;;
*)
echo -e "暂时不支持该${WORKSPACE}"
exit 2
;;
esac
done

# docker swarm节点信息,当然此部分可以利用ansible等其他方式进行统一管理,只是因为想要实现类似于kubectl exec 的效果,但又使用不了RBAC
declare -A nodesMsg
nodesMsg["docker-node-01"]="username::password::port"
nodesMsg["docker-node-02"]="username::password::port"
nodesMsg["docker-node-03"]="username::password::port"
nodesMsg["..."]="username::password::port"

botstudio.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#/bin/bash
#参数设定区域
cd $(dirname $0)
#加载配置文件
. ../config/common_bot_config
. ../config/botstudio_config
#常规变量,此处省略
#常规路径变量,此处也省略
#每次deploy所产生的镜像名称
# IMAGE_NAME=harbor地址/项目分支/${ProjectName}:${image_tag}
#遍历所有变量
for WORKSPACE in ${WorkspaceName}
do
#声明字典
declare -A $(echo ${WORKSPACE})
#遍历所有Key
for Key in $(eval echo '$'{!${WORKSPACE}Botstudio[@]})
do
#检查配置
if [ ! "$(eval echo '$'{${WORKSPACE}Botstudio[$Key]})" ];then
echo -e "\033[31mERROR:\033[0m ${ProjectName} ${WORKSPACE}${WORKSPACE}Botstudio[$Key] 配置出错,请添加配置或进行修改"
exit 3
fi
#获取所有key到公共变量
eval ${WORKSPACE}[$Key]=$(eval echo "'$'{${WORKSPACE}Botstudio[$Key]}")
done
done
#加载模块区域
. /etc/init.d/functions
. ../moudle/Help
. ../moudle/swarm_status
. ../moudle/swarm_stop
. ../moudle/swarm_start
. ../moudle/swarm_release
. ../moudle/swarm_exec
#逻辑程序区域
if [ "$1" == "status" ];then
[ "$2" ] && WorkspaceName="$2"
status_processes
elif [ "$1" == "stop" ];then
[ "$2" ] && WorkspaceName="$2"
stop_processes
elif [ "$1" == "start" ];then
[ "$2" ] && WorkspaceName="$2"
start_processes
elif [ "$1" == "restart" ];then
[ "$2" ] && WorkspaceName="$2"
stop_processes
start_processes
elif [ "$1" == "exec" ];then
[ "$2" ] || {
echo "Must input workspaceNum before exec docker"
exit 2
}
[ "$2" ] && WorkspaceName="$2"
exec_processes
elif [ "$1" == "help" ];then
cgmanage_help
else
#获取
ARGS=$(getopt -a -o f:t:p:h -l deploy,rollback,start,help,file:,time:,password: -- "$@")
#防止变量里有命令未能执行
eval set -- "${ARGS}"
while true
do
case "$1" in
--deploy)
Action="deploy"
;;
--rollback)
Action="rollback"
;;
--start)
ActionStatus="start"
;;
-t|--time)
RollbackTime="$2"
shift
;;
-p|--password)
ChangePassword="$2"
shift
;;
-h|--help)
cgmanage_help
;;
--)
[ "$2" ] && WorkspaceName="$2"
echo "${WorkspaceName}" | grep -q ','
if [[ $? -eq 0 ]];then
IFS=',' read -r -a WorkspaceName <<< "${WorkspaceName}"
fi
WorkspaceName="${WorkspaceName[@]}"
shift
break
;;
esac
shift
done
main_function
fi
docker-compose-swarm.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
services:
${WORKSPACEName}:
image: "${IMAGE_NAME}"
stop_grace_period: "${StopGracePeriod}"
user: "${LOCAL_UID}:${LOCAL_GID}"
env_file:
- ${StartupParameters}
environment:
- 特别的环境变量=xxx
# 在容器内可以使用的swarm的变量:
# 服务ID:{{.Service.ID}}
# 服务名称:{{.Service.Name}}
# 节点ID:{{.Node.ID}}
# 节点名称:{{.Node.Hostname}}
# TaskID:{{.Task.ID}}
# TaskName:{{.Task.Name}}
# TaskSlot:{{.Task.Slot}}
ports:
# 基于docker swarm默认NodePort方式进行轮询,外部利用各节点负载均衡,内部利用副本数负载均衡
- "所有节点对外提供服务的端口:docker容器内部服务监听的端口"
volumes:
# docker swarm支持Config文件挂载,hostpath(需保证部署所在的机子上有对应的文件夹)
- "宿主机目录:docker容器内部目录"
# 把本机的docker.sock挂载上去,主要是为了实现能实时获取被调度到哪台机子的节点信息,虽然后续是要通过swarm的config获取master的docker-api的方式进行具体的调用
- /var/run/docker.sock:/var/run/docker.sock:r
extra_hosts:
# 域名解析
- "域名":"ip"
networks:
# 基于不同服务之间进行网络隔离
- ${ProjectName}
- monitoring
healthcheck:
# 应用的健康检查
test: [ "CMD", "python", "-c", "import requests; requests.get('${SERVICE_HEALTHCHECK_ADDRESS}').raise_for_status()" ]
interval: 5s
timeout: 5s
retries: 3
logging:
driver: "json-file"
options:
max-size: "1G"
max-file: "3"
deploy:
mode: ${ServiceMode} # 部署方式,deployment还是damonset
replicas: ${ProjectEveryNum} # 副本数,damonset不可用
endpoint_mode: vip # 提供给外部分别与端口对应的vip
placement:
constraints:
- # 进行部署的节点限制性,必须满足,可以配置节点信息或者节点标签
- ${key}==${value}
preferences:
- # 基于节点的label进行亲和性的选择,spread为是否拥有对应的标签
- spread: ${value}
restart_policy:
condition: any # 重启策略,退出状态码不正常才重试
delay: 0s # 每次重试的间隔时间
max_attempts: 99999999 # 重试尝试次数
window: 5s # 决定重试的缓冲时间
rollback_config: # 当更新配置失败时如何回滚策略
parallelism: 0 # 回滚时同时进行的数量,0则为所有
delay: 5s # 当每个parallelism组回滚之后的间隔时间
failure_action: pause # 当回滚失败时的操作,目前为终止
monitor: 10s # 当每个parallelism回滚操作之后的监控时间
max_failure_ratio: 0 # 回滚失败率,0为不允许回滚失败
order: stop-first # 回滚过程,是否先停现有才开始新的,目前为启动新的才停掉旧的
update_config:
parallelism: ${ProjectEveryNum} # 一组一次更新的副本数,对应就是多少个task
delay: 5s # 当每个parallelism组更新之后的间隔时间
failure_action: pause # 如果更新失败的操作,目前为执行上述的回滚操作
monitor: 10s # 当每个parallelism更新操作之后的监控时间
max_failure_ratio: 0 # 更新期间允许的失败率
order: stop-first # 更新过程,是否先停现有才开始新的,目前为启动新的才停掉旧的
resources:
limits: # 最多
cpus: '待定'
memory: '待定'
reservations: # 至少
cpus: '待定'
memory: '待定'
networks:
${BOT_STACK_NAME}:
driver: overlay
external: true
monitoring:
driver: overlay
external: true
attachable: true
# 此处volume还打算上分布式存储(GlusterFS),在下一篇文档中进行补坑
swarm_release
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
#!/bin/bash

#先备份到文件夹,然后进行解压、更新配置、停止程序、备份旧代码、新代码更新、启动程序

#发布并且启动项目
function main_function() {
if [ "$Action" == "deploy" ];then
release_code
elif [ "$Action" == "rollback" ];then
rollback_code
fi
}

#发布deploy
function release_code() {
verification_deploy_key
clean_old_processes
update_config
stop_processes
backup_old_code
release_new_code
deploy_code
if [[ "${ActionStatus}" == "start" ]];then
start_processes
fi
}

#回滚rollback
function rollback_code() {
verification_deploy_key
clean_old_processes
backup_old_code
rollback_time
stop_processes
deploy_code
if [[ "${ActionStatus}" == "start" ]];then
start_processes
fi
}

#KEY和密码验证
function verification_deploy_key() {
if [ ! ${ChangePassword} ];then
read -t 60 -s -p "Please enter the key : " KeyWord
echo ""
else
KeyWord="${ChangePassword}"
fi
KeyWordMd5=$(echo "${KeyWord}" | md5sum | awk '{print $1}')
if [ "${ReleaseKey}" != "${KeyWordMd5}" ];then
echo -e "\033[31;1m Sorry,The key is wrong ! \033[0m"
exit 2
fi
}

#更新线上配置
function update_config() {
for WORKSPACE in ${WorkspaceName}
do
echo -e "${WORKSPACE} :"
ProjectsConfigPath=${BackupReleasePath}/${Time}/${ProjectName}/${WORKSPACE}
StartupParametersConfigPath=${ProjectsConfigPath}/${StartupParameters}
LaunchTemplateConfigPath=${ProjectsConfigPath}/${LaunchTemplate}
# 拷贝一份配置
if [ ! -d ${ProjectsConfigPath} ];then
mkdir -p ${ProjectsConfigPath}
fi
if [ ! -f ${StartupParametersConfigPath} ];then
cp -f ${DefaultDeployFileRoot}/${gitName}/${StartupParameters} ${ProjectsConfigPath}/
fi
if [ ! -f ${LaunchTemplateConfigPath} ]; then
cp -f ${DefaultDeployFileRoot}/${gitName}/${LaunchTemplate} ${ProjectsConfigPath}/
fi
for Key in $(eval echo '$'{!${WORKSPACE}[@]})
do
# swarm.env
# echo -e "\n\nswarm.env:"
value="$(eval echo '$'{${WORKSPACE}[$Key]})"
echo "${value}" | grep -q '@'
if [[ $? -eq 0 ]];then
echo "${value}" | grep '@' | grep -q '\\@'
if [[ $? -ne 0 ]];then
value=$(echo "${value}" | sed 's+\@+\\@+g')
fi
fi
echo "${value}" | grep -q '&'
if [[ $? -eq 0 ]];then
echo "${value}" | grep '&' | grep -q '\\&'
if [[ $? -ne 0 ]];then
value=$(echo "${value}" | sed 's+\&+\\&+g')
fi
fi
# swarm.env
SedResult=$(sed -n 's@\(\<'"${Key}"'\>\)\(=\)\(.*\)@\1\2'"${value}"'@p' ${StartupParametersConfigPath})
if [ "${SedResult}" ];then
sed -i 's@\(\<'"${Key}"'\>\)\(=\)\(.*\)@\1\2'"${value}"'@; s@^M@@g' ${StartupParametersConfigPath}
echo "1更改配置为: ${SedResult}"
fi
# docker-compose-swarm.yml
SedResult=$(sed -n 's@\(.*\)\(\${'"${Key}"'}\)\(.*\)@\1'"${value}"'\3@p' ${LaunchTemplateConfigPath})
if [ "${SedResult}" ];then
sed -i 's@\(.*\)\(\${'"${Key}"'}\)\(.*\)@\1'"${value}"'\3@; s@^M@@g' ${LaunchTemplateConfigPath}
echo "2更改配置为: ${SedResult}"
fi
done
# docker-compose-swarm.yml
# echo -e "\n\ndocker-compose-swarm.yml:"
while IFS='=' read -r key value; do
# 跳过空行和注释
echo "${value}" | grep -q '@'
if [[ $? -eq 0 ]];then
echo "${value}" | grep '@' | grep -q '\\@'
if [[ $? -ne 0 ]];then
value=$(echo "${value}" | sed 's+\@+\\@+g')
fi
fi
echo "${value}" | grep -q '&'
if [[ $? -eq 0 ]];then
echo "${value}" | grep '&' | grep -q '\\&'
if [[ $? -ne 0 ]];then
value=$(echo "${value}" | sed 's+\&+\\&+g')
fi
fi
[[ -z "$key" || "$key" =~ ^# ]] && continue
SedResult=$(sed -n 's@\(.*\)\(\${'"${key}"'}\)\(.*\)@\1'"${value}"'\3@p' ${LaunchTemplateConfigPath})
if [ "${SedResult}" ];then
sed -i 's@\(.*\)\(\${'"${key}"'}\)\(.*\)@\1'"${value}"'\3@; s@^M@@g' ${LaunchTemplateConfigPath}
echo "3更改配置为: ${SedResult}"
fi
done < ${StartupParametersConfigPath}
# 替换应用名
SedResult=$(sed -n 's@\(.*\)\(\${ProjectName}\)\(.*\)@\1'"${ProjectName}"'\3@p' ${LaunchTemplateConfigPath})
if [ "${SedResult}" ];then
sed -i 's@\(.*\)\(\${ProjectName}\)\(.*\)@\1'"${ProjectName}"'\3@; s@^M@@g' ${LaunchTemplateConfigPath}
echo "4更改配置为: ${SedResult}"
fi
# 替换环境变量配置文件名
SedResult=$(sed -n 's@\(.*\)\(\${StartupParameters}\)\(.*\)@\1'"${StartupParameters}"'\3@p' ${LaunchTemplateConfigPath})
if [ "${SedResult}" ];then
sed -i 's@\(.*\)\(\${StartupParameters}\)\(.*\)@\1'"${StartupParameters}"'\3@; s@^M@@g' ${LaunchTemplateConfigPath}
echo "5更改配置为: ${SedResult}"
fi
# botstudio.sh
# 替换镜像
IMAGE_NAME=$(cat "${DefaultDeployFileRoot}"/"${gitName}"/${DeploymentDocumentation} | grep "three" | awk -F "three:" '{for (i = 2; i <= NF; i++) printf "%s" , $i }' | sed 's/^[ \t]*//;s/[ \t]*$//' | awk -F "@-@" '{print $2}')
SedResult=$(sed -n 's@\(.*\)\(\${IMAGE_NAME}\)\(.*\)@\1'"${IMAGE_NAME}"'\3@p' ${LaunchTemplateConfigPath})
if [ "${SedResult}" ];then
sed -i 's@\(.*\)\(\${IMAGE_NAME}\)\(.*\)@\1'"${IMAGE_NAME}"'\3@; s@^M@@g' ${LaunchTemplateConfigPath}
echo "6更改配置为: ${SedResult}"
fi
# 替换网络
SedResult=$(sed -n 's@\(.*\)\(\${ProjectName}\)\(.*\)@\1'"${ProjectName}"'\3@p' ${LaunchTemplateConfigPath})
if [ "${SedResult}" ];then
sed -i 's@\(.*\)\(\${ProjectName}\)\(.*\)@\1'"${ProjectName}"'\3@; s@^M@@g' ${LaunchTemplateConfigPath}
echo "6更改配置为: ${SedResult}"
fi
# 替换版本号
HARBOR_URL=$(cat "${DefaultDeployFileRoot}"/"${gitName}"/${DeploymentDocumentation} | grep "three" | awk -F "three:" '{for (i = 2; i <= NF; i++) printf "%s" , $i }' | sed 's/^[ \t]*//;s/[ \t]*$//' | awk -F "@-@" '{print $1}')
cat ~/.docker/config.json | grep "${HARBOR_URL}"
[[ $? == 0 ]] && {
docker logout "${HARBOR_URL}"
}
harbor_username=$(cat "${DefaultDeployFileRoot}"/"${gitName}"/${DeploymentDocumentation} | grep "two" | awk -F "two:" '{for (i = 2; i <= NF; i++) printf "%s" , $i }' | sed 's/^[ \t]*//;s/[ \t]*$//' | awk -F "@-@" '{print $1}' | base64 --decode)
harbor_password=$(cat "${DefaultDeployFileRoot}"/"${gitName}"/${DeploymentDocumentation} | grep "two" | awk -F "two:" '{for (i = 2; i <= NF; i++) printf "%s" , $i }' | sed 's/^[ \t]*//;s/[ \t]*$//' | awk -F "@-@" '{print $2}' | base64 --decode)
docker login -u "${harbor_username}" -p "${harbor_password}" "${HARBOR_URL}"
docker pull ${IMAGE_NAME}
IMAGE_REPOSITORY=$(echo -n "${IMAGE_NAME}" | awk -F ":" '{print $1}')
IMAGE_TAG=$(echo -n "${IMAGE_NAME}" | awk -F ":" '{print $2}')
IMAGE_ID=$(docker image ls | grep "${IMAGE_REPOSITORY}" | grep "${IMAGE_TAG}" | awk '{print $3}')
IMAGE_CREATE_TIME=$(docker inspect "${IMAGE_ID}" | jq '.[] | .Created' | sed "s/\"//g")
# DATE_PART=$(echo ${IMAGE_CREATE_TIME} | awk -F'T' '{print $1}')
# TIME_PART=$(echo ${IMAGE_CREATE_TIME} | awk -F'T' '{print $2}' | sed 's/Z//')
VERSION_TIMESTAMP=$(date -d "${IMAGE_CREATE_TIME}" +%s)
SedResult=$(sed -n 's@\(.*\)\(\${CKT_BOT_CODE_VERSION}\)\(.*\)@\1'"${VERSION_TIMESTAMP}"'\3@p' ${LaunchTemplateConfigPath})
if [ "${SedResult}" ];then
sed -i 's@\(.*\)\(\${CKT_BOT_CODE_VERSION}\)\(.*\)@\1'"${VERSION_TIMESTAMP}"'\3@; s@^M@@g' ${LaunchTemplateConfigPath}
echo "6更改配置为: ${SedResult}"
fi
done
}

#备份旧代码
function backup_old_code() {
for WORKSPACE in ${WorkspaceName}
do
#先确认是否存在备份旧代码
if [ ! -d ${ProjectPath}/${WORKSPACE} ];then
echo -e "Can't find the old code , \033[31;1m Skip backup \033[0m"
continue
fi
#进行备份操作
mkdir ${BackupProjectPath}/${Time}/${WORKSPACE} -p || echo -e "\033[31;1m Create backup projects dir fail \033[0m"
mv ${ProjectPath}/${WORKSPACE} ${BackupProjectPath}/${Time}/ || {
echo -e "Backup ${Identifier} ${WORKSPACE} old code \033[31;1;5m False \033[0m"
exit 2
}
#再次确认
if [ -d ${BackupProjectPath}/${Time}/${WORKSPACE} ];then
echo -e "Backup ${Identifier} ${WORKSPACE} old code \033[32;1m OK \033[0m"
fi
done
}

# 基于新的配置deploy
function release_new_code() {
[[ -d ${ProjectPath} ]] || {
mkdir -p ${ProjectPath}
}
for WORKSPACE in ${WorkspaceName}
do
mv ${BackupReleasePath}/${Time}/${ProjectName}/${WORKSPACE} ${ProjectPath}/ || {
echo -e "\033[31;1m Release New Code fail \033[0m"
echo "ERROR : Can not move ${BackupReleasePath}/${Time}/${ProjectName}/${WORKSPACE} to ${ProjectPath}/"
exit 2
}
if [ -d ${ProjectPath}/${WORKSPACE} ];then
echo -e "Release new code \033[32;1m OK \033[0m "
fi
done
}

# 清理历史的镜像和容器,避免占空间
function clean_old_processes() {
LeaderNode=$(docker node ls | grep "Ready" | grep "Leader" | awk '{print $3}')
OtherNode=$(docker node ls | grep "Ready" | grep -v "Leader" | awk '{print $2}')
for node in ${LeaderNode[@]}
do
NodeIp=$(docker node inspect ${node} | jq '.[] | .Status.Addr' | sed "s/\"//g")
username=$(echo -n "${nodesMsg[${node}]}" | awk -F "::" '{print $1}' | base64 --decode)
password=$(echo -n "${nodesMsg[${node}]}" | awk -F "::" '{print $2}' | base64 --decode)
port=$(echo -n "${nodesMsg[${node}]}" | awk -F "::" '{print $3}' | base64 --decode)
sshpass -p "${password}" ssh -o StrictHostKeyChecking=no -p ${port} -tt "${username}@${NodeIp}" "docker system prune -f"
if [[ $? -eq 0 ]];then
echo -e "Clean ${Identifier} ${node} \033[32;1m OK \033[0m"
else
echo -e "Clean ${Identifier} ${node} wrong \n"
fi
done
for node in ${OtherNode[@]}
do
NodeIp=$(docker node inspect ${node} | jq '.[] | .Status.Addr' | sed "s/\"//g")
username=$(echo -n "${nodesMsg[${node}]}" | awk -F "::" '{print $1}' | base64 --decode)
password=$(echo -n "${nodesMsg[${node}]}" | awk -F "::" '{print $2}' | base64 --decode)
port=$(echo -n "${nodesMsg[${node}]}" | awk -F "::" '{print $3}' | base64 --decode)
sshpass -p "${password}" ssh -o StrictHostKeyChecking=no -p ${port} -tt "${username}@${NodeIp}" "docker system prune -f"
if [[ $? -eq 0 ]];then
echo -e "Clean ${Identifier} ${node} \033[32;1m OK \033[0m"
else
echo -e "Clean ${Identifier} ${node} wrong \n"
fi
done
}

# 部署新的配置
function deploy_code() {
# 先检查网络部分
ResultCount=$(docker network ls | grep "${ProjectName}")
if [[ "${ResultCount}" == "" ]];then
docker network create --driver overlay "${ProjectName}"
fi
for WORKSPACE in ${WorkspaceName}
do
Key="CKT_BOT_STACK_NAME"
stackName="$(eval echo '$'{${WORKSPACE}[$Key]})"
echo -e "${WORKSPACE} :"
ProjectsConfigPath=${ProjectPath}/${WORKSPACE}
LaunchTemplateConfigPath=${ProjectsConfigPath}/${LaunchTemplate}
docker stack deploy -c ${LaunchTemplateConfigPath} --with-registry-auth "${stackName}"
ResultCount=$(docker stack ls | grep "${stackName}")
if [[ "${ResultCount}" != "" ]];then
echo -e "Create ${Identifier} ${stackName} ${WORKSPACE} \033[32;1m OK \033[0m"
else
echo -e "Create ${Identifier} ${stackName} ${WORKSPACE} wrong \n"
continue
fi
done
}

swarm_rollback
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/bin/bash!

function rollback_time () {
if [[ ! -z "${RollbackTime}" ]];then
BackupProjectPath=$(find "${BackupProjectPath}" -maxdepth 1 -type d -name "${RollbackTime}" -exec readlink -f {} \;)
elif [[ -z "${RollbackTime}" ]];then
BackupProjectPath=$(ls -dt ${BackupProjectPath}/* | head -n 1)
fi
[[ "${BackupProjectPath}" != "" ]] || {
echo -e "\033[31mERROR:\033[0m ${Identifier} history version: ${RollbackTime} or last version is not exist"
exit 1
}
[[ -d ${ProjectPath} ]] || {
mkdir -p ${ProjectPath}
}
for WORKSPACE in ${WorkspaceName}
do
cp -rf ${BackupProjectPath}/${WORKSPACE} ${ProjectPath}/ || {
echo -e "\033[31;1m Rollback old Code fail \033[0m"
echo "ERROR : Can not move ${BackupProjectPath}/${WORKSPACE} to ${ProjectPath}"
exit 2
}
if [[ -d ${ProjectPath}/${WORKSPACE} ]];then
echo -e "Rollback old code \033[32;1m OK \033[0m "
fi
done

}
swarm_start
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#!/bin/bash
#启动模块
function start_processes() {
for WORKSPACE in ${WorkspaceName}
do
Key="CKT_BOT_STACK_NAME"
stackName="$(eval echo '$'{${WORKSPACE}[$Key]})"
local ResultInfo=$(docker stack ls | grep "${stackName}" | head -n 1 | awk '{print $1}' | grep -w "${stackName}\$")
local ResultCount=$(echo "${ResultInfo}" | wc -l)
if [ -z "${ResultInfo}" ];then
echo "● ${DescriptionHead}"
echo -e "Identifier: ${Identifier} ${stackName} ${WORKSPACE} is \033[31;1m not exist(dead) \033[0m"
continue
fi
ResultInfo=$(docker service ls | grep "${stackName}_${WORKSPACE}")
TotalStatus=$(echo "${ResultInfo}" | awk '{print $4}')
RunningStatus=$(echo "${TotalStatus}" | awk -F "/" '{print $1}')
ExpectStatus=$(echo "${TotalStatus}" | awk -F "/" '{print $2}')
Key="CKT_BOT_REPLICAS_MAX"
ProjectEveryNum="$(eval echo '$'{${WORKSPACE}[$Key]})"
if [ ${RunningStatus} -eq ${ExpectStatus} ] && [ "${ExpectStatus}" -eq "${ProjectEveryNum}" ];then
echo -e "Identifier: ${Identifier} ${stackName} ${WORKSPACE} \033[32;1m active (running) \033[0m"
continue
elif [[ "${ExpectStatus}" -ne "${ProjectEveryNum}" ]];then
# 开始启动service
docker service scale "${stackName}_${WORKSPACE}"=${ProjectEveryNum}
echo -e "change ${Identifier} ${stackName} ${WORKSPACE} num to ${ProjectEveryNum} \033[32;1m OK \033[0m"
count=0
while true
do
sleep 10s
ResultInfo=$(docker service ls | grep "${stackName}_${WORKSPACE}")
TotalStatus=$(echo "${ResultInfo}" | awk '{print $4}')
RunningStatus=$(echo "${TotalStatus}" | awk -F "/" '{print $1}')
ExpectStatus=$(echo "${TotalStatus}" | awk -F "/" '{print $2}')
if [[ ${RunningStatus} -eq ${ExpectStatus} ]];then
echo -e "start ${Identifier} ${stackName} ${WORKSPACE} \033[32;1m OK \033[0m"
break
fi
((counter++))
if [[ ${counter} -eq 6 ]];then
echo -e "Try to start ${Identifier} ${stackName} ${WORKSPACE} ${counter} 次 but \033[31;1m Error \033[0m"
break
fi
done
else
while true
do
sleep 10s
ResultInfo=$(docker service ls | grep "${stackName}_${WORKSPACE}")
TotalStatus=$(echo "${ResultInfo}" | awk '{print $4}')
RunningStatus=$(echo "${TotalStatus}" | awk -F "/" '{print $1}')
ExpectStatus=$(echo "${TotalStatus}" | awk -F "/" '{print $2}')
if [[ ${RunningStatus} -eq ${ExpectStatus} ]];then
echo -e "start ${Identifier} ${stackName} ${WORKSPACE} \033[32;1m OK \033[0m"
break
fi
((counter++))
if [[ ${counter} -eq 6 ]];then
echo -e "Try to start ${Identifier} ${stackName} ${WORKSPACE} but \033[31;1m Error \033[0m"
break
fi
done
fi
done
}
swarm_status
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#!/bin/bash

#检查状态模块
function status_processes() {

for WORKSPACE in ${WorkspaceName}
do
Key="CKT_BOT_STACK_NAME"
stackName="$(eval echo '$'{${WORKSPACE}[$Key]})"
# 从docker stack中查看状态
local ResultInfo=$(docker stack ls | grep "${stackName}" | head -n 1 | awk '{print $1}' | grep -w "${stackName}\$")
local ResultCount=$(echo "${ResultInfo}" | wc -l)
if [ -z "${ResultInfo}" ];then
echo "● ${DescriptionHead}"
echo -e "Identifier: ${Identifier} ${stackName} ${WORKSPACE} is \033[31;1m not exist(dead) \033[0m"
continue
fi
if [[ ${ResultCount} -ge 1 ]];then
ResultInfo=$(docker service ls | grep "${stackName}_${WORKSPACE}")
TotalStatus=$(echo "${ResultInfo}" | awk '{print $4}')
RunningStatus=$(echo "${TotalStatus}" | awk -F "/" '{print $1}')
ExpectStatus=$(echo "${TotalStatus}" | awk -F "/" '{print $2}')
NetworkName=$(docker network ls | grep "${ProjectName}" | awk '{print $1}')
NetworksInfo=$(docker service inspect "${stackName}_${WORKSPACE}" | jq '.[] | .Spec.TaskTemplate.Networks' | jq '.[] | select(.Target | contains("'"${NetworkName}"'")) | .Target' | sed "s/\"//g")
if [ ${RunningStatus} -eq ${ExpectStatus} ] && [ ${ExpectStatus} -gt 0 ];then
# 开始运行时间
LastStartTime=$(docker service inspect "${stackName}_${WORKSPACE}" | grep "UpdatedAt" | cut -d '"' -f 4 | awk -F "." '{print $1}' | sed "s/T/ /g")
# 运行的状态信息
RunningStatusInfos=$(docker service ps --no-trunc --format "{{.Name}}@@@{{.Node}}@@@{{.DesiredState}}@@@{{.CurrentState}}@@@{{.Error}}" "${stackName}_${WORKSPACE}" | grep "Running")
# 正在运行的节点
# RuningWorkstation=$(echo "${RunningStatusInfo}" | grep "Running" | awk -F "@@@" '{print $1}' | uniq | tr '\n' ',')
# 总运行时长(截止到目前)
# EndStartTime=$(echo "${RunningStatusInfo}" | grep "Running" | awk -F "@@@" '{print $3}' | sed "s/ago//g" | tr '\n' ',')
# 端口映射关系
PortMapping=$(docker service ls | grep "${stackName}_${WORKSPACE}" | awk '{for (i=6; i<=NF; i++) printf "%s ", $i; print ""}')
RunningNodes=$(echo "${RunningStatusInfos}" | awk -F "@@@" '{print $2}' | uniq)
declare -A NetworkInfo
for node in "${RunningNodes[@]}"
do
username=$(echo -n "${nodesMsg[${node}]}" | awk -F "::" '{print $1}' | base64 --decode)
password=$(echo -n "${nodesMsg[${node}]}" | awk -F "::" '{print $2}' | base64 --decode)
port=$(echo -n "${nodesMsg[${node}]}" | awk -F "::" '{print $3}' | base64 --decode)
NodeIp=$(docker inspect ${node} | jq '.[] | .Status.Addr' | sed "s/\"//g")
NetworkInfo["${node}"]=$(sshpass -p "${password}" ssh -o StrictHostKeyChecking=no -p "${port}" -tt "${username}@${NodeIp}" "docker network inspect ${NetworksInfo}" 2>/dev/null)
done
echo -e "\033[32;1m ● \033[0m ${DescriptionHead} "
while IFS= read -r line; do
RunningName=$(echo "${line}" | awk -F "@@@" '{print $1}')
RunningStatus=$(echo "${line}" | awk -F "@@@" '{print $2}')
EndStartTime=$(echo "${line}" | awk -F "@@@" '{print $4}' | sed "s/ago//g" | sed "s/Running//g")
RuningWorkstation=$(echo "${line}" | awk -F "@@@" '{print $2}')
RunningReason=$(echo "${line}" | awk -F "@@@" '{print $NF}')
NetworkIp=$(echo "${NetworkInfo[$RuningWorkstation]}" | jq '.[] | .Containers '| jq '.[] | select(.Name | contains("'"${RunningName}"'")) | .IPv4Address' | sed "s/\"//g")
echo -e " Identifier: ${Identifier} ${RunningName} active \033[32;1m ${RunningStatus} \033[0m since \033[32;1m ${LastStartTime} \033[0m respective in \033[32;1m ${EndStartTime} \033[0m"
echo -e " Running Node is respective in: \033[32;1m ${RuningWorkstation} \033[0m"
echo -e " Running Ip is : \033[32;1m ${NetworkIp} \033[0m"
if [ "$RunningReason" != "" ];then
echo -e " Maybe some reason output in: \033[32;1m ${RunningReason} \033[0m"
fi
echo -e " Port Mapping: ${PortMapping}\n"
done <<< "${RunningStatusInfos}"
elif [ ${RunningStatus} -eq ${ExpectStatus} ] && [ ${ExpectStatus} -eq 0 ];then
echo -e "\033[32;1m ● \033[0m ${DescriptionHead} "
echo -e " Identifier: ${Identifier} ${stackName} ${WORKSPACE} active \033[31;1m Not Running \033[0m...\n"
else
echo "● ${DescriptionHead} "
echo -e "Now ${Identifier} ${stackName} Running in ${RunningStatus} and expect in ${ExpectStatus}"
LastStartTime=$(docker service inspect "${stackName}_${WORKSPACE}" | grep "UpdatedAt" | cut -d '"' -f 4 | awk -F "." '{print $1}' | sed "s/T/ /g")
PortMapping=$(docker service ls | grep "${stackName}_${WORKSPACE}" | awk '{for (i=6; i<=NF; i++) printf "%s ", $i; print ""}')
for index in $(seq 1 ${ExpectStatus}); do
RunningNum=1
RunningNum_1=$(($RunningNum+1))
RunningStatusInfos=$(docker service ps --no-trunc --format "{{.Name}}@@@{{.Node}}@@@{{.DesiredState}}@@@{{.CurrentState}}@@@{{.Error}}" "${stackName}_${WORKSPACE}" | grep "${stackName}_${WORKSPACE}.${index}" | head -n ${RunningNum})
RunningReason=$(echo "${RunningStatusInfos}" | awk -F "@@@" '{print $5}')
if [ "${RunningReason}" == "" ];then
RunningStatusInfos=$(docker service ps --no-trunc --format "{{.Name}}@@@{{.Node}}@@@{{.DesiredState}}@@@{{.CurrentState}}@@@{{.Error}}" "${stackName}_${WORKSPACE}" | grep "${stackName}_${WORKSPACE}.${index}" | head -n ${RunningNum_1} | tail -n ${RunningNum} )
fi
RunningName=$(echo "${RunningStatusInfos}" | awk -F "@@@" '{print $1}')
RuningWorkstation=$(echo "${RunningStatusInfos}" | awk -F "@@@" '{print $2}' | uniq)
RunningStatus=$(echo "${RunningStatusInfos}" | awk -F "@@@" '{print $3}')
if [ "${RunningStatus}" == "Running" ];then
EndStartTime=$(echo "${RunningStatusInfos}" | awk -F "@@@" '{print $4}' | sed "s/ago//g" | sed "s/Running//g")
fi
RunningReason=$(echo "${RunningStatusInfos}" | awk -F "@@@" '{print $5}')
declare -A NetworkInfo
for node in "${RuningWorkstation[@]}"
do
username=$(echo -n "${nodesMsg[${node}]}" | awk -F "::" '{print $1}' | base64 --decode)
password=$(echo -n "${nodesMsg[${node}]}" | awk -F "::" '{print $2}' | base64 --decode)
port=$(echo -n "${nodesMsg[${node}]}" | awk -F "::" '{print $3}' | base64 --decode)
NodeIp=$(docker inspect ${node} | jq '.[] | .Status.Addr' | sed "s/\"//g")
NetworkInfo["${node}"]=$(sshpass -p "${password}" ssh -o StrictHostKeyChecking=no -p "${port}" -tt "${username}@${NodeIp}" "docker network inspect ${NetworksInfo}" 2>/dev/null)
done
NetworkIp=$(echo "${NetworkInfo[$RuningWorkstation]}" | jq '.[] | .Containers '| jq '.[] | select(.Name | contains("'"${RunningName}"'")) | .IPv4Address' | sed "s/\"//g")
echo "${RunningName} Detailed description: "
if [ "${RunningStatus}" == "Running" ];then
echo -e "Identifier: ${Identifier} ${RunningName} active \033[32;1m ${RunningStatus} \033[0m since \033[32;1m ${LastStartTime} \033[0m respective in \033[32;1m ${EndStartTime} \033[0m"
else
echo -e "Identifier: ${Identifier} ${RunningName} active \033[32;1m ${RunningStatus} \033[0m since \033[32;1m ${LastStartTime} \033[0m"
fi
echo -e "Running Node is respective in: \033[32;1m ${RuningWorkstation} \033[0m"
echo -e "Running Ip is : \033[32;1m ${NetworkIp} \033[0m"
echo -e "Running status is: \033[31;1m ${RunningStatus} \033[0m"
if [ "$RunningReason" != "" ];then
echo -e "Maybe some reason output in: \033[31;1m ${RunningReason} \033[0m"
fi
echo -e " Port Mapping: ${PortMapping}\n"
echo "----------------------------------------------------------------"
#echo -e "Identifier: ${Identifier} ${ProjectName} ${WORKSPACE} has something \033[31;1m wrong \033[0m and not runing in expectations \n"
done
fi
fi
done
}
swarm_stop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#!/bin/bash
#stop module
function stop_processes() {
for WORKSPACE in ${WorkspaceName}
do
Key="BOT_STACK_NAME"
stackName="$(eval echo '$'{${WORKSPACE}[$Key]})"
local ResultInfo=$(docker stack ls | grep "${stackName}" | head -n 1 | awk '{print $1}' | grep -w "${stackName}\$")
local ResultCount=$(echo "${ResultInfo}" | wc -l)
if [ -z "${ResultInfo}" ];then
echo "● ${DescriptionHead}"
echo -e "Identifier: ${Identifier} ${stackName} ${WORKSPACE} is \033[31;1m not exist(dead) \033[0m"
continue
fi
ResultInfo=$(docker service ls | grep "${stackName}_${WORKSPACE}")
TotalStatus=$(echo "${ResultInfo}" | awk '{print $4}')
RunningStatus=$(echo "${TotalStatus}" | awk -F "/" '{print $1}')
ExpectStatus=$(echo "${TotalStatus}" | awk -F "/" '{print $2}')
Key="BOT_REPLICAS_MIN"
ProjectEveryNum="$(eval echo '$'{${WORKSPACE}[$Key]})"
if [ ${RunningStatus} -eq ${ExpectStatus} ] && [ "${ExpectStatus}" -eq "${ProjectEveryNum}" ];then
echo -e "Identifier: ${Identifier} ${stackName} ${WORKSPACE} \033[32;1m no running (dead) \033[0m"
continue
elif [[ "${ExpectStatus}" -ne "${ProjectEveryNum}" ]];then
# 开始关闭service
docker service scale "${stackName}_${WORKSPACE}"=${ProjectEveryNum}
echo -e "change ${Identifier} ${stackName} ${WORKSPACE} num to ${ProjectEveryNum} \033[32;1m OK \033[0m"
count=0
while true
do
sleep 10s
ResultInfo=$(docker service ls | grep "${stackName}_${WORKSPACE}")
TotalStatus=$(echo "${ResultInfo}" | awk '{print $4}')
RunningStatus=$(echo "${TotalStatus}" | awk -F "/" '{print $1}')
ExpectStatus=$(echo "${TotalStatus}" | awk -F "/" '{print $2}')
if [[ ${RunningStatus} -eq ${ExpectStatus} ]];then
echo -e "stop ${Identifier} ${stackName} ${WORKSPACE} \033[32;1m OK \033[0m"
break
fi
((counter++))
if [[ ${counter} -eq 6 ]];then
echo -e "Try to stop ${Identifier} ${stackName} ${WORKSPACE} ${counter} 次 but \033[31;1m Error \033[0m"
break
fi
done
else
count=0
while true
do
sleep 10s
ResultInfo=$(docker service ls | grep "${stackName}_${WORKSPACE}")
TotalStatus=$(echo "${ResultInfo}" | awk '{print $4}')
RunningStatus=$(echo "${TotalStatus}" | awk -F "/" '{print $1}')
ExpectStatus=$(echo "${TotalStatus}" | awk -F "/" '{print $2}')
if [[ ${RunningStatus} -eq ${ExpectStatus} ]];then
echo -e "stop ${Identifier} ${stackName} ${WORKSPACE} \033[32;1m OK \033[0m"
break
fi
((counter++))
if [[ ${counter} -eq 6 ]];then
echo -e "Try to stop ${Identifier} ${stackName} ${WORKSPACE} ${counter} 次 but \033[31;1m Error \033[0m"
break
fi
done
fi
done
}
swarm_exec
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#!/bin/bash
#stop module
function exec_processes() {
for WORKSPACE in ${WorkspaceName}
do
Key="BOT_STACK_NAME"
stackName="$(eval echo '$'{${WORKSPACE}[$Key]})"
ResultInfo=$(docker stack ls | grep "${stackName}")
if [[ "${ResultInfo}" == "" ]];then
echo -e "\033[32;1m ● \033[0m ${DescriptionHead} "
echo -e " Identifier: ${Identifier} ${stackName} ${WORKSPACE} is \033[31;1m Not Existed \033[0m...\n"
exit 2
fi
ResultInfo=$(docker service ls | grep "${stackName}_${WORKSPACE}")
TotalStatus=$(echo "${ResultInfo}" | awk '{print $4}')
RunningStatus=$(echo "${TotalStatus}" | awk -F "/" '{print $1}')
# 建议先安装jq
if [[ ${RunningStatus} -eq 1 ]];then
NodeName=$(docker service ps "${stackName}_${WORKSPACE}" | grep "Running" | awk '{print $4}')
NodeIp=$(docker inspect ${NodeName} | jq '.[] | .Status.Addr' | sed "s/\"//g")
ContainerdName=$(curl -s http://${NodeIp}:${NodePort}/containers/json | jq '.[] | select((.Names[] | contains("'"${stackName}"'_'"${WORKSPACE}"'")) and (.state = "running")) | .Id' | head -n 1 | sed "s/\"//g")
elif [[ ${RunningStatus} -gt 1 ]];then
NodeName=$(docker service ps "${stackName}_${WORKSPACE}" | grep "Running" | awk '{print $4}' | uniq | tr '\n' ',')
echo "需要进入哪个节点上的容器进行直接或间接的访问:(可供选择为${NodeName},不填则默认第一个)"
read -t 30 -p "请输入节点名称(默认):" NodeName
if [[ "${NodeName}" == "" ]];then
NodeName=$(docker service ps "${stackName}_${WORKSPACE}" | grep "Running" | awk '{print $4}' | uniq | head -n 1)
fi
docker node ls | grep "${NodeName}"
if [[ $? -ne 0 ]];then
echo -e "\033[32;1m ● \033[0m ${DescriptionHead} "
echo -e " Identifier: ${Identifier} ${stackName} ${WORKSPACE} is \033[31;1m not in ${NodeName} \033[0m"
exit 2
fi
NodeIp=$(docker inspect ${NodeName} | jq '.[] | .Status.Addr' | sed "s/\"//g")
ContainerdName=$(curl -s http://${NodeIp}:${NodePort}/containers/json | jq '.[] | select((.Names[] | contains("'"${stackName}"'_'"${WORKSPACE}"'")) and (.state = "running")) | .Id' | head -n 1 | sed "s/\"//g")
else
echo -e "\033[32;1m ● \033[0m ${DescriptionHead} "
echo -e " Identifier: ${Identifier} ${stackName} ${WORKSPACE} active \033[31;1m Not Running \033[0m...\n"
exit 2
fi
read -t 30 -p "需要以什么终端形式进入容器(默认bash):" mode
if [[ "${mode}" == "" ]];then
mode="bash"
fi
username=$(echo -n "${nodesMsg[${NodeName}]}" | awk -F "::" '{print $1}' | base64 --decode)
password=$(echo -n "${nodesMsg[${NodeName}]}" | awk -F "::" '{print $2}' | base64 --decode)
port=$(echo -n "${nodesMsg[${NodeName}]}" | awk -F "::" '{print $3}' | base64 --decode)
sshpass -p "${password}" ssh -o StrictHostKeyChecking=no -p ${port} -tt "${username}@${NodeIp}" "docker exec -it ${ContainerdName} /bin/${mode}"
done
}