在AliCloud Serverless Kubernetes集群Gitlab Runner部署笔记

阿里云 Serverless Kubernetes 让您无需管理和维护集群与服务器,即可快速创建 Kuberentes 容器应用,并且根据应用实际使用的 CPU 和内存资源量进行按需付费。使用 Serverless Kubernetes,您可以专注于设计和构建应用程序,而不是管理运行应用程序的基础设施。它基于阿里云弹性计算基础架构,并且完全兼容 Kuberentes API 的解决方案,充分结合了虚拟化资源带来的安全性、弹性和 Kubernetes 生态。

由此定位,这种集群是很适合用来跑CI流程场景的。CI触发时创建对应资源,CI结束后销毁对应的资源。目前Serverless Kubernetes集群尚在公测当中,或多或少有一些不友好的体验,比如:

  • 不支持 RoleRoleBinding
  • 不能自定义CoreDNS/Kube-DNS配置。
  • 不能使用docker-in-docker方式构建镜像。
  • 不支持 PersistentVolumePersistentVolumeClaim

以上提及的四点就是本次部署Runner时需要解决的需求。

不支持 Role,RoleBinding

在触发CI流程时,Runner会在Kubenertes集群中创建对应的Pod进行CI,在不支持自定义 RoleRoleBinding的情况下,也就只有使用阿里云提供的kubeconfig文件了,将对应值粘贴到对应字段创建Secret,这里不再累述。最后Runner会引用到这个Secret

apiVersion: v1
kind: Secret
metadata:
  name: kubernetes-admin-cert
type: kubernetes.io/tls
data:
  ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUq......
  tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR......
  tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQp......

不能自定义CoreDNS/Kube-DNS配置

自定义CoreDNS/Kube-DNS配置是为了让集群内部应用不通过公网访问同一VPC下的其他应用直接通过内网即可,比如Gitlab,Harbor等。

解决方式一:

阿里云官方提供的解决方案是使用privateZone。但本文不介绍这种方式,为什么呢?这是一个谜一样的问题,这里不做深入探讨。

解决方式二:

👋注意:该方法Serverless Kubernetes集群尚不支持,未来将会支持,故现在解决此问题只能用方式一。

让Runner所生成的Pod使用HostAliases。但是官方提供的Runner并不支持这个功能,那就直接优化源码吧,优化详情参见此次提交

不能使用docker-in-docker方式构建镜像

解决方式:

使用kaniko进行镜像构建,这里我们将官方镜像中的可执行文件复制到自己的CI镜像中即可使用。

FROM gcr.io/kaniko-project/executor:v0.9.0
FROM registry.cn-hangzhou.aliyuncs.com/choerodon-tools/cibase:0.7.0
COPY --from=0 /kaniko/executor /usr/local/bin/kaniko

这是我build好可直接食用的镜像:

registry.cn-hangzhou.aliyuncs.com/setzero/gitlab-ci-slaver:0.1.0

待友好解决的问题:

  • Harbor界面不显示镜像信息issues,但如果原本就有该镜像的仓库那么是可以正常显示的。疑是Harbor版本太低的问题,目前使用的是v1.4.0。
  • 执行kaniko后会出现Deleting filesystem...操作,导致执行完kaniko后不能再执行其他命令,在CI中可以再分出一个stage来规避这个问题。

不支持 PV 和 PVC

在CI时我们需要缓存一些可复用的文件,或者上一job所产生的文件下个job会用到。

解决方式一:

先部署minio,minio通过nfs volume方式挂载nas,然后在.gitlab-ci.yml文件中使用cacheartifacts关键字。但本文不介绍这种方式,为什么呢?这是一个谜一样的问题,这里不做深入探讨。

相关资料:

解决方式二:

让Runner所生成的Pod使用nfs volume方式挂载nas,但是官方提供的Runner并不支持这个功能,那就直接优化源码吧,优化详情参见此次MR,故将这次CI生成的二进制文件覆盖官方原有的就行。

FROM gitlab/gitlab-runner:alpine-v11.8.0
ADD https://gitlab.com/TimeBye/gitlab-runner/-/jobs/174588999/artifacts/raw/out/binaries/gitlab-runner-linux-amd64 /usr/bin/gitlab-ci-multi-runner
RUN chmod +x /usr/bin/gitlab-ci-multi-runner

这是我build好可直接食用的镜像:

registry.cn-hangzhou.aliyuncs.com/setzero/gitlab-runner:alpine-v11.8.1

后记

优化Runner后的配置示例

concurrent = 3
check_interval = 0
[[runners]]
  name = "runner"
  url = "https://gitlab.com/"
  token = "2b388a2636d35b9d141348e972706b"
  executor = "kubernetes"
  output_limit = 51200
  environment = ["CHART_REPOSITORY=http://chart.com",
                 "SONAR_URL=http://sonarqube.com"]
  [runners.kubernetes]
    host = "https://abcde.serverless-1.kubernetes.cn-shanghai.aliyuncs.com:6443"
    cert_file = "/etc/gitlab-runner/tls.crt"
    key_file = "/etc/gitlab-runner/tls.crt"
    ca_file = "/etc/gitlab-runner/ca.crt"
    namespace = "default"
    pull_policy = "always"
    cpu_limit = "2"
    cpu_request = "2"
    memory_limit = "4Gi"
    memory_request = "4Gi"
    service_cpu_limit = "1"
    service_cpu_request = "1"
    service_memory_limit = "2Gi"
    service_memory_request = "2Gi"
    helper_cpu_limit = "250m"
    helper_cpu_request = "250m"
    helper_memory_limit = "512Mi"
    helper_memory_request  = "512Mi"
    helper_image = "gitlab/gitlab-runner-helper:x86_64-3fff1dcf"
    [runners.kubernetes.pod_annotations]
     # "k8s.aliyun.com/enable-eip" = "true"
    [runners.kubernetes.host_aliases]
      "127.0.0.1" = [ "foo.local", "bar.local" ]
      "127.0.0.2" = [ "oof.local", "rab.local" ]
    [runners.kubernetes.volumes]
      [[runners.kubernetes.volumes.nfs]]
        name = "runner-cache"
        mount_path = "/cache"
        server = "abcde-map64.cn-shanghai.nas.aliyuncs.com"
        nfs_path = "/runner/cache-pv"
      [[runners.kubernetes.volumes.nfs]]
        name = "runner-maven"
        mount_path = "/root/.m2"
        server = "abcde-map64.cn-shanghai.nas.aliyuncs.com"
        nfs_path = "/runner/maven-pv"
      [[runners.kubernetes.volumes.secret]]
        name = "docker-registry-secret"
        mount_path = "/root/.docker"
        read_only = false
        [runners.kubernetes.volumes.secret.items]
          "config.json" = "config.json"