ssh客户端配置

拉取ssh镜像

1
docker pull testcontainers/sshd:latest

启动容器

1
docker run -it --name sshd testcontainers/sshd:latest sh

配置服务器密钥

生成密钥

1
ssh-keygen -t rsa -b 4096

生成后选择存储路径,回车默认即可

存储密钥后输入密码,由于是自动化脚本无需设置,直接回车

复制密钥

1
ssh-copy-id user@remote_host

执行后输入yes确定链接

连接后输入password完成连接

执行命令

非交互式命令

1
ssh user@remote_host 'ls -l /path/to/directory'

文件传输

1
scp local_file user@remote_host:/path/to/remote/directory

打包容器并将镜像上传仓库

若无需上传私有仓库可跳过此步骤

打包容器

1
docker commit sshd registry_host/sshd:latest

registry_host为镜像仓库地址

登录远程仓库

1
docker login registry_host

按照提示输入用户名和密码

推送镜像

1
docker push registry_host/sshd:latest

配置Gitness

关于基础项目创建与仓库配置可参考Gitness文档,这边不再赘述。

配置流水线脚本之前先去对应的流水线设置触发器,不然就会出现脚本配置完成但是推送不触发流水线的尴尬情况= =

配置处在Pipelines -> 三个点 -> Settings -> Triggers

本机拉取镜像出错解决方法

如果你的镜像仓库和Gitness在同一台主机或者网络环境下,且配置了反向代理,才会出现这个问题

直接按照域名/镜像名称拉取会报错Error response from daemon: Get "https://域名/v2/": net/http: TLS handshake timeout

这个时候需要更改拉取方式,将拉取地址修改为内网IP:端口/镜像名称

同时修改配置/etc/docker/daemon.json

1
2
3
{
  "insecure-registries": ["内网IP:端口"]
}

并重启docker

登陆时使用内网IP:端口进行登录,在后期拉取时也使用内网IP:端口/镜像名称进行拉取

配置完毕后,只有跟镜像在同一台主机或网络环境下的拉取与推送需要切换拉取方式,其他主机依旧使用域名进行拉取或推送,登录同理

流水线时实践

启动前可以先手动拉取drone/git:latest与其他所需镜像,避免Gitness直接拉取失败。

Hugo自动化部署

流水线配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
kind: pipeline
spec:
  stages:
    - type: ci
      spec:
        steps:
          - name: prod
            type: run
            spec:
              container: registry_host/sshd:latest
              privileged: true
              script: |-
                ssh -t -o StrictHostKeyChecking=no user@host 'cd /website/InitCompose && bash blog.sh'                

脚本文件配置

blog.sh
1
2
docker compose run --rm hugo sh /script/hugo.sh
docker restart blog-nginx
 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
#!/bin/sh

# 定义变量
REPO_DIR="/repo"
REPO_URL="https://username:token@仓库路径.git"
BRANCH="master"
SRC_DIR="/src"

# 检查 REPO_DIR 是否存在,如果不存在则创建它
if [ ! -d "$REPO_DIR" ]; then
  echo "$REPO_DIR 不存在,开始创建..."
  mkdir -p "$REPO_DIR"
fi

# 检查路径中是否有现有的 git 仓库
if [ -d "$REPO_DIR/.git" ]; then
  echo "Git 仓库存在,将删除并重新克隆..."

  # 删除现有仓库
  rm -rf "$REPO_DIR"

  # 重新创建目录
  mkdir -p "$REPO_DIR"
fi

# 进入目录
cd "$REPO_DIR" || { echo "进入目录失败"; exit 1; }

echo "正在克隆仓库..."

# 克隆远程仓库
git clone "$REPO_URL" .

# 检查克隆是否成功
if [ $? -ne 0 ]; then
  echo "克隆远程仓库失败"
  exit 1
fi

# 切换到指定分支
git checkout "$BRANCH" || { echo "切换到分支 $BRANCH 失败"; exit 1; }

# 删除 src 目录下的所有内容
echo "删除 $SRC_DIR 下的所有内容..."
rm -rf "$SRC_DIR/*"

# 复制 WebBlog 目录下的内容到 src 目录
echo "将 $REPO_DIR/WebBlog 下的内容复制到 $SRC_DIR..."
cp -rf "$REPO_DIR/WebBlog/"* "$SRC_DIR/"

# 确保复制操作成功
if [ $? -ne 0 ]; then
  echo "复制文件失败"
  exit 1
fi

# 确保 hugo 已经安装
if ! command -v hugo > /dev/null 2>&1; then
  echo "hugo 命令未找到,请确保 hugo 已经安装"
  exit 1
fi

cd "$SRC_DIR" || { echo "进入目录失败"; exit 1; }

echo "重新构建 hugo 站点..."
rm -rf public

hugo

echo "构建完成"

操作完成后,Gitness会在每次提交自动化部署,极大减少每次博客更新发布的复杂度

Java项目部署

需要准备好一个配置好目标主机ssh密钥的ssh客户端镜像

 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
kind: pipeline
spec:
  options:
    envs:
      PROJECT_NAME: <项目名>
      USER_NAME: <ssh 用户名>
      HOST_NAME: <ssh 主机名>
      SERVER_PORT: <服务端口>
  stages:
    - type: ci
      spec:
        volumes:
          - name: resp
            spec:
              path: /root/.m2/repository
            type: host

          - name: cache
            spec: {}
            type: temp
        steps:
          - name: build
            type: run
            spec:
              container: maven:3.9.8-sapmachine-17
              privileged: true
              mount:
                - name: cache
                  path: /tmp

                - name: resp
                  path: /root/.m2/repository
              script: |-
                mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V
                mvn test -B
                mkdir -p /tmp/maven-build
                cp ${PROJECT_NAME}/target/*.jar /tmp/maven-build/                
              artifacts:
                - ${PROJECT_NAME}/target/*.jar
          - name: mkdir
            type: run
            spec:
              container: <镜像仓库域名>/ssh:latest
              privileged: true
              script: ssh -t ${USER_NAME}@${HOST_NAME} "rm -r /website/${PROJECT_NAME}/backend && mkdir -p /website/${PROJECT_NAME}/backend"
          - name: push-run
            type: run
            spec:
              container: <镜像仓库域名>/ssh:latest
              privileged: true
              mount:
                - name: cache
                  path: /tmp
              script: |-
                scp -o StrictHostKeyChecking=no /tmp/maven-build/${PROJECT_NAME}.jar ${USER_NAME}@${HOST_NAME}:/website/${PROJECT_NAME}/backend

                ssh -t ${USER_NAME}@${HOST_NAME} "docker rm -f java-${SERVER_PORT} && docker run --name java-${SERVER_PORT} -v /website/${PROJECT_NAME}/backend:/website/${PROJECT_NAME}/backend -p ${SERVER_PORT}:${SERVER_PORT} --restart always -d bellsoft/liberica-openjdk-debian:17 sh -c 'java -jar /website/${PROJECT_NAME}/backend/${PROJECT_NAME}.jar'"                

前端(Nginx)项目部署

 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
kind: pipeline
spec:
  options:
    envs:
      PROJECT_NAME: <项目名>
      USER_NAME: <ssh 用户名>
      HOST_NAME: <ssh 主机名>
      SERVER_PORT: <服务端口>
  stages:
  - type: ci
    spec:
      volumes:
      - name: resp
        spec: 
          path: /root/.node/node_modules
        type: host

      - name: cache
        spec: {}
        type: temp
      steps:
      - name: build
        type: run
        spec:
          container: node:16.20.2
          privileged: true
          mount:
          - name: cache
            path: /tmp

          - name: resp
            path: /gitness/node_modules
          script: |-
            npm install
            npm run build:prod
            cp -r dist /tmp/node-build
            ls /tmp/node-build            
      - name: mkdir
        type: run
        spec:
          container: <镜像仓库域名>/ssh:latest
          privileged: true
          script: ssh -t ${USER_NAME}@${HOST_NAME} "rm -r -f /website/${PROJECT_NAME}/frontend && mkdir -p /website/${PROJECT_NAME}/frontend"
      - name: push-run
        type: run
        spec:
          container: <镜像仓库域名>/ssh:latest
          privileged: true
          mount:
          - name: cache
            path: /tmp
          script: |-
            scp -r -o StrictHostKeyChecking=no /tmp/node-build ${USER_NAME}@${HOST_NAME}:/website/${PROJECT_NAME}/frontend
            
            ssh -t ${USER_NAME}@${HOST_NAME} "docker rm -f node-${SERVER_PORT} && docker run --name node-${SERVER_PORT} -v /website/${PROJECT_NAME}/frontend/node-build:/usr/share/nginx/html -p ${SERVER_PORT}:80 --restart always -d nginx:latest"