1. 前置条件

  1. 准备好任意版本的 KubeSphere 并开启 devops 功能

  2. 自行解决操作过程中因为网路异常而导致的一些意料之外的错误,例如无法访问github

2. 构建流程

注意!实测window会构建失败,因为代码里面会用到一些Shell脚本语法window无法识别会出错,因此本章节所有的构建操作流程都需要在Linux环境中完成。

2.1 构建 builder-base

2.1.1 拉取代码

我们需要从github拉取官方的基础环境代码,重新构建它才能支持更高级的nodejs版本

git clone https://github.com/kubesphere/devops-agent/tree/master

root@ubuntu:~# cd ~
root@ubuntu:~# mkdir build
root@ubuntu:~# cd build/
root@ubuntu:~/build# git clone https://github.com/kubesphere/devops-agent.git
Cloning into 'devops-agent'...
remote: Enumerating objects: 330, done.
remote: Counting objects: 100% (128/128), done.
remote: Compressing objects: 100% (76/76), done.
remote: Total 330 (delta 88), reused 66 (delta 50), pack-reused 202 (from 1)
Receiving objects: 100% (330/330), 73.78 KiB | 1.01 MiB/s, done.
Resolving deltas: 100% (147/147), done.
root@ubuntu:~/build# cd devops-agent/
root@ubuntu:~/build/devops-agent# ll
total 84
drwxr-xr-x 11 root root  4096 Sep 12 10:22 ./
drwxr-xr-x  3 root root  4096 Sep 12 10:22 ../
drwxr-xr-x  4 root root  4096 Sep 12 10:22 base/
drwxr-xr-x  2 root root  4096 Sep 12 10:22 dotnet/
-rwxr-xr-x  1 root root   314 Sep 12 10:22 .editorconfig*
drwxr-xr-x  8 root root  4096 Sep 12 10:22 .git/
drwxr-xr-x  4 root root  4096 Sep 12 10:22 .github/
-rw-r--r--  1 root root   154 Sep 12 10:22 .gitignore
-rw-r--r--  1 root root   193 Sep 12 10:22 .gitpod.Dockerfile
-rw-r--r--  1 root root   425 Sep 12 10:22 .gitpod.yml
drwxr-xr-x  4 root root  4096 Sep 12 10:22 go/
drwxr-xr-x  3 root root  4096 Sep 12 10:22 gradle/
-rw-r--r--  1 root root 11357 Sep 12 10:22 LICENSE
-rw-r--r--  1 root root  1269 Sep 12 10:22 Makefile
drwxr-xr-x  3 root root  4096 Sep 12 10:22 maven/
drwxr-xr-x  3 root root  4096 Sep 12 10:22 nodejs/
-rw-r--r--  1 root root   433 Sep 12 10:22 OWNERS
drwxr-xr-x  3 root root  4096 Sep 12 10:22 python/
-rw-r--r--  1 root root  3970 Sep 12 10:22 README.md
root@ubuntu:~/build/devops-agent# 

2.1.2 编辑 Dockerfile

这里需要描述一下 centos7 是不能直接运行 nodejs18 或者更高级别的版本的,会出现 GLIBC_2.27 not found 之类的异常错误,我们肯定不能对 glibc 进行升级因为服务器可能还运行着其他的软件,冒然升级可能会导致服务器宕机这是非常危险的。

因为官方Dockerfile中的FROM基础镜像是 centos7 因此我们需要对它进行变更,不然打出来的nodejs也是会同样出现 glibc 异常错误的。

Downloading and installing node v20.11.1...
Downloading https://nodejs.org/dist/v20.11.1/node-v20.11.1-linux-x64.tar.xz...
######################################################################## 100.0%
Computing checksum with sha256sum
Checksums matched!
node: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by node)
node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by node)
node: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by node)
node: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by node)
node: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by node)
node: /lib64/libc.so.6: version `GLIBC_2.25' not found (required by node)
nvm is not compatible with the npm config "prefix" option: currently set to ""
Run `nvm use --delete-prefix v20.11.1` to unset it.

因此我们需要变更成为 AlmaLinux 9.4 它和 CentOS 7.9 的对比如下:

  • 内核版本:AlmaLinux 9.4 使用更新的内核,性能和安全性更好;CentOS 7.9 内核较旧。

  • 生命周期:AlmaLinux 9.4 支持到 2032 年;CentOS 7.9 支持到 2024 年。

  • 软件版本:AlmaLinux 9.4 提供更新的软件包和库;CentOS 7.9 的软件版本相对过时。

  • 系统工具:AlmaLinux 9.4 支持现代管理工具如 podman,CentOS 7.9 以传统工具为主。

  • glibc 版本:AlmaLinux 9.4 使用 glibc 2.34,提供更好的性能和新功能支持;CentOS 7.9 使用 glibc 2.17,版本较老,对现代软件的兼容性较差。

拉取代码完成后 cd base 进去这个目录,编辑 Dockerfile 文件将第一行 centos:7 换成 almalinux:9.4

因为 almalinux:9.4 缺少了语言环境相关的依赖包需要补全,不然后面运行会出警告,glibc-locale-source,glibc-langpack-zh,glibc-langpack-en

2.1.3 开始构建

docker build -t tanqidi/builder-base:almalinux-9.4 .

构建的过程会出现一些红色的异常信息,实际它不影响构建。

image-azjt.png

2.2 构建 nodejs 任意版本

构建完 builder-base 基础镜像之后我们就可以基于它来构建任意版本的nodejs了,可以看到FROM第一行引用的就是上面构建出来的基础镜像。

2.2.1 编辑 Dockerfile

https://nodejs.org/dist/

可以看到主要变更 NODE_VERSION 变量,变更成为你想要的版本号即可,这里我选择 18.20.4

FROM tanqidi/builder-base:almalinux-9.4

# 下载并安装 Node.js 18
ENV NODE_VERSION=18.20.4
RUN curl -fsSL https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.xz -o node.tar.xz \
    && tar -xJf node.tar.xz -C /usr/local --strip-components=1 \
    && rm node.tar.xz

# 验证 Node.js 和 npm 是否安装成功
RUN node -v && npm -v

2.2.2 开始构建

docker build -t tanqidi/builder-nodejs:almalinux9.4-node18.20.4 .

不出意外就构建好了

image-gypn.png

3. 使用方式

3.1 编辑 ConfigMap

来到KubeSphere配置字典,切换到 kubesphere-devops-system 编辑 jenkins-casc-config 这个 ConfigMap,养成好习惯在编辑的时候先把这份配置文件下载到本地改错了还能直接覆盖回去。

image-ecib.png

这个 ConfigMap 有2个文件进入第一个文件找到 name: "nodejs" 的,整个复制一份然后编辑三个地方

image-ukgx.png

注意对齐将这份配置好的 almalinux9.4-node18.20.4 分别放到上面截图中的 jenkins.yaml 和 jenkins_user.yaml 里面即可。

- name: "almalinux9.4-node18.20.4"
  namespace: "kubesphere-devops-worker"
  label: "almalinux9.4-node18.20.4"
  nodeUsageMode: "EXCLUSIVE"
  idleMinutes: 0
  containers:
  - name: "nodejs"
    image: "registry.cn-hangzhou.aliyuncs.com/tanqidi/builder-nodejs:almalinux9.4-node18.20.4"
    command: "cat"
    args: ""
    ttyEnabled: true
    privileged: false
    resourceRequestCpu: "100m"
    resourceLimitCpu: "4000m"
    resourceRequestMemory: "100Mi"
    resourceLimitMemory: "8192Mi"
  - name: "jnlp"
    image: "registry.cn-beijing.aliyuncs.com/kubesphereio/inbound-agent:4.10-2"
    args: "^${computer.jnlpmac} ^${computer.name}"
    resourceRequestCpu: "50m"
    resourceLimitCpu: "500m"
    resourceRequestMemory: "400Mi"
    resourceLimitMemory: "1536Mi"
  workspaceVolume:
    emptyDirWorkspaceVolume:
      memory: false
  volumes:
  - hostPathVolume:
      hostPath: "/var/run/docker.sock"
      mountPath: "/var/run/docker.sock"
  - hostPathVolume:
      hostPath: "/var/data/jenkins_nodejs_yarn_cache"
      mountPath: "/root/.yarn"
  - hostPathVolume:
      hostPath: "/var/data/jenkins_nodejs_npm_cache"
      mountPath: "/root/.npm"
  - hostPathVolume:
      hostPath: "/var/data/jenkins_sonar_cache"
      mountPath: "/root/.sonar/cache"
  yaml: |
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
              - key: node-role.kubernetes.io/worker
                operator: In
                values:
                - ci
      tolerations:
      - key: "node.kubernetes.io/ci"
        operator: "Exists"
        effect: "NoSchedule"
      - key: "node.kubernetes.io/ci"
        operator: "Exists"
        effect: "PreferNoSchedule"
      containers:
      - name: "nodejs"
        resources:
          requests:
            ephemeral-storage: "1Gi"
          limits:
            ephemeral-storage: "10Gi"
      securityContext:
        fsGroup: 1000 

3.2 流水线配置

不用重启Jenkins等一会流水线就能识别到新的构建环境选项了,可以看到我这里完美运行成功了,你也来尝试一下吧!

image-qvki.png

image-pqlp.png

4. 镜像制品

我已经将镜像上传到dockerhub和阿里云了可以直接使用。

  1. tanqidi/builder-base:almalinux-9.4

  2. tanqidi/builder-nodejs:almalinux9.4-node18.20.4

  3. registry.cn-hangzhou.aliyuncs.com/tanqidi/builder-base:almalinux-9.4

  4. registry.cn-hangzhou.aliyuncs.com/tanqidi/builder-nodejs:almalinux9.4-node18.20.4

5. 操作总结

除了使用方式编辑ConfigMap这一步骤有点抽象之外我相信其他的操作对于你来说都是手拿把掐的,本章不仅限能全版本构建nodejs,你还能以此发散思维拓展diy任意的构建环境,包括但不限于更高版本的maven,gradle,go之类的。