分类: 云原生

  • 为 Harbor 配置 OIDC 以使用 Keycloak 登录

    事实上,主要准备工作都在 Keycloak 侧。如果还未准备好 Keycloak,可以参考本文进行部署:在 Kubernetes 中部署 Keycloak

    配置 Keycloak

    图文可能有助于理解,这里不会给出可导出导入的配置文件。

    必要时,新建 Realm

    根据需要,可以考虑新建一个 Realm 进行隔离。

    需要注意的是,用户不能跨 Realm 共享。

    新建用户和组

    我们可以利用 Keycloak 中 Groups 的特性,后续配置 Harbor 可以将特定组成员视为管理员。

    这里将新建一个用户,名为 domain:

    然后新建一个 harbor 组,在它下级再新建 admin 组。

    别忘了,将用户加入对应组:

    新建 Client scopes 和 Mapper

    默认情况下,组信息不会被带出,因此我们需要配置 Client scopes 和 Mapper 使得 Keycloak 可以在用户信息中体现用户组信息。

    新建一个名为 groups 的 Client scope,考虑到不是所有 Client 都需要透出用户的所属组信息,所以这里配置为 Optional 类型。

    然后新建一个 Group Membership 类型的 Mapper,透出用户所属组:

    只需要在用户信息里带上所属组信息:

    Token Claim Name 可以根据需求起名,后续需要告知 Harbor 从该字段确认是否管理员组。

    新建 Client 并关联 Client scope

    这里新建一个名为 harbor 的 Client,回调地址需要正确配置否则无法登录。

    关联刚才新建的 Client scope,类型可选择 Default,这样 Harbor 不需要显式指定。

    配置 Harbor

    这侧只需要按文档配置就可以了:Harbor docs | Configure OIDC Provider Authentication。下面给出示例:

    调试

    这类配置一般不会一帆风顺,因此合适的调试手段可以有效帮助我们解决问题。

    Keycloak 用户信息

    Client -> Client scopes -> Evaluate 中可以模拟登录回调后生成的用户信息。有助于我们检查用户信息字段映射的结果是否符合预期。

    harbor-core 日志

    登录流程中产生的非预期行为一般会在这里输出错误或警告日志,我们针对性找到根因处理即可。

  • 在 Kubernetes 中部署 Keycloak

    随着 bitnami 放弃维护开源的社区版本 charts,Keycloak 部署的相对较优方案则应当考虑官方的 Operator。

    具体文档参见 Keycloak Operator Installation – Keycloak。早期 Keycloak Operator 依赖 olm 进行安装和管理,现在新版允许直接通过 yaml 安装了,可以自行选择。

    安装 Operator Lifecycle Manager

    如果选择通过 olm 管理 Keycloak Operator,那么可以参考 QuickStart | Operator Lifecycle Manager,可以使用 operator-sdk 或者 yaml 进行安装。

    等待 olm 安装并就绪。

    安装 Keycloak Operator(使用 olm)

    olm 就绪后,你可以列出 Catalog Source:

    user@hostname:~# kubectl get catalogsources.operators.coreos.com -A
    NAMESPACE   NAME                    DISPLAY               TYPE   PUBLISHER        AGE
    olm         operatorhubio-catalog   Community Operators   grpc   OperatorHub.io   5d

    记下这个名字 operatorhubio-catalog,然后让 LLM 根据文档 Keycloak Operator Installation – Keycloak 帮我们生成 Keycloak CRD yaml。

    ---
    apiVersion: operators.coreos.com/v1
    kind: OperatorGroup
    metadata:
      name: keycloak-operators
      namespace: keycloak
    spec:
      targetNamespaces:
      - keycloak
    ---
    apiVersion: operators.coreos.com/v1alpha1
    kind: Subscription
    metadata:
      name: keycloak-operator
      namespace: keycloak
    spec:
      channel: fast
      name: keycloak-operator
      source: operatorhubio-catalog
      sourceNamespace: olm
      installPlanApproval: Manual

    这里需要手动批准才会继续执行安装:

    user@hostname:~# kubectl get installplans.operators.coreos.com -A
    NAMESPACE   NAME            CSV                         APPROVAL   APPROVED
    keycloak    install-97p69   keycloak-operator.v26.6.3   Manual     false
    
    user@hostname:~# kubectl -n keycloak edit installplans.operators.coreos.com install-97p69

    spec.approved 修改为 true,保存并退出即可。此时应该可以看到 Operator 开始运行。

    user@hostname:~# kubectl -n keycloak get po
    NAME                                 READY   STATUS    RESTARTS   AGE
    keycloak-operator-5dc6b64db4-7sqxs   1/1     Running   0          5d

    安装 Keycloak

    同理,让 AI 根据 kubectl explain 结果生成 yaml,先生成骨架,然后按需求逐步添加调度、数据库 TLS、反代请求头等参数,下面给出一份可用示例。

    ---
    apiVersion: k8s.keycloak.org/v2beta1
    kind: Keycloak
    metadata:
      name: keycloak
      namespace: keycloak
    spec:
      instances: 1
      scheduling:
        affinity:
          nodeAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
              nodeSelectorTerms:
              - matchExpressions:
                - key: kubernetes.io/hostname
                  operator: In
                  values:
                  - node-name
        tolerations:
        - key: node.kubernetes.io/unschedulable
          operator: Exists
          effect: NoSchedule
      db:
        vendor: mysql
        host: mysql.example.com
        port: 3306
        database: keycloak
        usernameSecret:
          name: keycloak-db
          key: username
        passwordSecret:
          name: keycloak-db
          key: password
      truststores:
        database-tls-ca:
          configMap:
            name: keycloak-database-tls-ca
      additionalOptions:
      - name: db-tls-mode
        value: verify-server
      - name: proxy-headers
        value: xforwarded
      http:
        httpEnabled: true
      hostname:
        hostname: keycloak.example.com

    这里也给出一份 Gateway 的示例,使用 Traefik,预先配置好 cert-manager 及其 Issuer:

    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: Gateway
    metadata:
      name: keycloak-gateway
      annotations:
        cert-manager.io/cluster-issuer: letsencrypt
    spec:
      gatewayClassName: traefik
      listeners:
      - hostname: keycloak.example.com
        name: websecure
        port: 8443
        protocol: HTTPS
        tls:
          certificateRefs:
          - name: keycloak-tls
    ---
    apiVersion: gateway.networking.k8s.io/v1
    kind: HTTPRoute
    metadata:
      name: keycloak-route
    spec:
      hostnames:
      - keycloak.example.com
      parentRefs:
      - name: keycloak-gateway
      rules:
      - matches:
        - path:
            type: PathPrefix
            value: /
        backendRefs:
        - name: keycloak-service
          port: 8080

    同时,可以到 MySQL 中验证一下连接是否已经开启了 TLS:

    SELECT 
        THREAD_ID, 
        PROCESSLIST_USER, 
        PROCESSLIST_HOST, 
        CONNECTION_TYPE 
    FROM performance_schema.threads 
    WHERE PROCESSLIST_USER IS NOT NULL;

    此时安装应该已经就绪,可以检查 Pod:

    user@hostname:~# kubectl -n keycloak get po
    NAME                                 READY   STATUS    RESTARTS   AGE
    keycloak-0                           1/1     Running   0          94m
    keycloak-operator-5dc6b64db4-7sqxs   1/1     Running   0          5d

    Pod 正常运行且检查日志无问题之后,即可获取初始临时管理员账密进行操作了。

    user@hostname:~# kubectl -n keycloak get secret keycloak-initial-admin -oyaml
  • 腾讯云轻量对象存储的简单体验

    腾讯云给轻量服务器锐驰型的用户发了相同时长的轻量对象存储 50G 免费额度,正好来体验一下。

    控制台上挂载到轻量服务器上使用

    控制台上面非常简洁,看起来基本上就是只希望客户使用这种方式了。使用门槛很低,只需要配置相同地域的服务器(不一定非要锐驰型)和路径就会自动帮忙挂载。

    底层也是 cosfs 实现的,应该是用 Agent 自动下发的挂载命令,对新手很友好。搭配 200M 的机器,对于个人开发者来说可以省下一笔不少的费用。

    这种方式没有什么更多要说的了,唯一可能要注意的事情是:部分修改文件可能会导致整个文件重传。更多类似限制,可以查阅 cosfs 的相关文档。另外,cosfs 也有了支持 posix 的后继者 GooseFS-Lite,参见这里。但未来趋势可能还是存储网关。

    当然了,对象存储更多的使用场景还是得通过 API 来进行存取,下面简单来尝试一下。还是有所要注意的地方的。

    通过 API/SDK 调用 – 以 Loki 为例

    看轻量对象存储的文档的话,会发现其实它还是支持 API/SDK 调用的,Endpoint 和标准的 COS 是一样的:

    那么我们就先来创建子账号和对应所需的权限。经过尝试,如果按照 lhcos(轻量对象存储)进行授权的话,通过 S3 兼容接口调用还是会报错 403,这里按 cos(标准对象存储)授权就可以了。这里也吐槽一下,由于这个 appid 不是用户主账号 uid,就没法使用对象存储的诊断工具了。

    {
        "statement": [
            {
                "action": [
                    "cos:GetBucket",
                    "cos:GetObject",
                    "cos:PutObject",
                    "cos:DeleteObject"
                ],
                "effect": "allow",
                "resource": [
                    "qcs::cos:<region>:uid/<uid>:<bucketName>-<uid>/*"
                ]
            }
        ],
        "version": "2.0"
    }

    配置 Loki 使用轻量对象存储,这里给出关键的配置片段:

    loki:
      storage:
        type: s3
        s3:
          endpoint: cos.ap-hongkong.myqcloud.com
          region: ap-hongkong
          accessKeyId: <ak>
          secretAccessKey: <sk>
        bucketNames:
          chunks: <bucketName>-<uid>
          ruler: <bucketName>-<uid>
          admin: <bucketName>-<uid>
      schemaConfig:
        configs:
          - from: 2024-04-01
            object_store: s3
            store: tsdb
            schema: v13
            index:
              prefix: index_
              period: 24h

    由于我这里是跨云的集群,如果 CoreDNS 不在内网会导致解析对象存储的 Endpoint 是公网 IP,会把账单打爆,所以这里还需要配置 DNS:(说明一下,这里不知道什么毛病,dnsConfig 居然用了 tpl 方法但是 values.yaml 里面又是个 map,所以只能喂个 string,然后部署的时候会有警告)

    singleBinary:
      replicas: 1
      nodeSelector:
        kubernetes.io/hostname: hkg-qcloud
      dnsConfig: |-
        nameservers:
          - 183.60.83.19
          - 183.60.82.98

    启动后发现 Loki 有报错,日志没有持久化:

    level=error ts=2025-04-23T08:34:33.088568269Z caller=flush.go:261 component=ingester loop=29 org_id=xxx msg="failed to flush" retries=1 err="failed to flush chunks: store put chunk: InvalidArgument: invalid x-cos-storage-class for role mode bucket, only support intellingent tiering or default\n\tstatus code: 400, request id: xxx, host id: , num_chunks: 1, labels: {app=\"loki\", component=\"gateway\", container=\"nginx\", filename=\"/var/log/pods/monitoring_loki-gateway-6fb5686c6f-42wcc_ce7d81e7-a5fb-4436-b2e8-51abf866f056/nginx/0.log\", instance=\"loki\", job=\"monitoring/loki\", namespace=\"monitoring\", node_name=\"hkg-qcloud\", pod=\"loki-gateway-6fb5686c6f-42wcc\", service_name=\"loki\", stream=\"stderr\"}"

    看起来是 Loki 在调用上传的时候,加了对象的预期存储类型,轻量对象存储可能刚好简化了这个类型。尝试从代码里面找的话, 可以发现确实支持进行配置:

    文档中也给出了相应说明:Grafana Loki configuration parameters | Grafana Loki documentation。所以我们可以新增配置:

    loki:
      storage_config:
        aws:
          storage_class: INTELLIGENT_TIERING

    问题解决。Loki 日志显示开始正常存取日志块,并且轻量对象存储控制台上也能看见相应的文件了。

    附录

    完整的 Loki values.yaml

    deploymentMode: SingleBinary
    loki:
      commonConfig:
        replication_factor: 1
      storage:
        type: s3
        s3:
          endpoint: cos.ap-hongkong.myqcloud.com
          region: ap-hongkong
          accessKeyId: <ak>
          secretAccessKey: <sk>
        bucketNames:
          chunks: <bucketName>-<uid>
          ruler: <bucketName>-<uid>
          admin: <bucketName>-<uid>
      storage_config:
        aws:
          storage_class: INTELLIGENT_TIERING
      schemaConfig:
        configs:
          - from: 2024-04-01
            object_store: s3
            store: tsdb
            schema: v13
            index:
              prefix: index_
              period: 24h
      limits_config:
        retention_period: 4320h
      compactor:
        retention_enabled: true
        delete_request_store: s3
    singleBinary:
      replicas: 1
      nodeSelector:
        kubernetes.io/hostname: hkg-qcloud
      dnsConfig: |-
        nameservers:
          - 183.60.83.19
          - 183.60.82.98
    chunksCache:
      enabled: false
    gateway:
      nodeSelector:
        kubernetes.io/hostname: hkg-qcloud
    resultsCache:
      enabled: false
    read:
      replicas: 0
    backend:
      replicas: 0
    write:
      replicas: 0
  • linuxserver/openssh-server mods

    最近希望给一个服务器启动一个独立的 openssh-server 容器用于安全转发内部接口请求,发现 linuxserver/openssh-server 镜像非常适合这一场景。

    不过这个镜像默认是不开启 TCP 转发的,官方提供了一个较为优雅的模块插件机制来实现类似功能,模块可以在这里找到:Linuxserver Container Mods。只要配置环境变量 DOCKER_MODS=linuxserver/mods:openssh-server-ssh-tunnel 就可以自动加载了。

    看起来模块只是一些脚本,具体的实现在这里:docker-mods/root/etc/s6-overlay/s6-rc.d/init-mod-openssh-server-ssh-tunnel-setup/run at f7fc561d103d6832bb75a4cb4f575b1166180430 · linuxserver/docker-mods · GitHub

    那么模块是怎么被拉取的呢,离线的私有化场景中怎么处理?可以在这里找到:docker-mods/docker-mods.v3 at cac9e7450a0698f19d750b67db61c4aa214d5290 · linuxserver/docker-mods

    也就是说,模块实际上都是 Docker 镜像,并且这个脚本已经支持了自定义制品库拉取,我们应该可以编写自己的模块,放到私仓,然后在离线环境中拉取并加载使用了。有空的时候来测试一下这个场景。

    引用

    For the ones who don’t know about the existence of Linuxserver Docker mods : r/selfhosted

  • 新版 K3s CNI 目录变化导致 Istio 安装失败

    最近在研究 Istio,在最新正式版的 K3s v1.31.5+k3s1 版本下,安装最新正式版 Istio 1.24.3 时,一直卡在 ztunnel 安装这里,于是来发个牢骚。

    现象

    使用 Helm 安装 ztunnel 之后,发现 ztunnel 无法调度,报错 IP 池不足:failed to allocate for range 0: no IP addresses available in range set。事实上每个节点上调度的 Pod 相当少,IP 不足是不可能的。而且在这之后,其它 Pod 如果重新调度,也会报同样错误,说明集群网络可能出现问题了。

    调查

    任选一个节点,发现 /var/lib/cni/networks/cbr0 目录下已经整个 IP 池被占用,没有释放。参考一个 Issue:pod creation failure: “no IP addresses available in range set” · Issue #4682 · k3s-io/k3s,尝试将 IP 释放,释放后发现,如果再次尝试安装 ztunnel 就会导致 IP 快速被耗尽,而且 ztunnel 的报错信息中有 CNI 组件相关内容(忘记截图),因此考虑 K3s 中是否有其它不同的因素导致其工作异常。

    经过一番搜寻之后发现 K3s 还真的有一个相关的变化,CNI bin dir changes with K3s version · Issue #10869 · k3s-io/k3s 这里引入了一个 CNI 路径的变化,从 /var/lib/rancher/k3s/data/current/bin/ 变为了 /var/lib/rancher/k3s/data/cni/

    一开始我看到 Rancher 当下的文档 Additional Steps for Installing Istio on RKE2 and K3s Clusters | Rancher 中提到的路径都是前者,就没有怀疑,看来问题就恰好出在这里。

    注意到 Istio 的 Helm Chart 中,有一个提交对此做出了适配:fix: fix k3s cniBinDir to static path (#54112) · istio/istio@7693f57 · GitHub,但是不幸的是还没有正式版的 Release,也就是说,当前安装的 Istio 1.24.3 仍然是旧的 CNI 路径,因此和较新版本的 K3s 不兼容。不过,我发现当下已经有 RC 版本(1.25.0-rc.0)的 Helm Chart 带上了这个变更,所以尝试清理 IP 池后,将 Istio 组件都更新到 1.25.0-rc.0,果然 ztunnel 成功运行了。

    引用

    Istio / Platform-Specific Prerequisites

    kubenet/kubelet leaks ips on docker restart · Issue #34278 · kubernetes/kubernetes

    kubenet ip泄漏 – xiaoqing blog

    「Bug」K8s 节点的 IP 地址泄漏,导致 IP 被耗尽 – 於清樂 – 博客园

    failed to allocate for range 0: no IP addresses available in range set: 172.20.xx.1-172.20.xx.254 – yuxiaoba – 博客园

    Containerd IP leakage · Issue #5768 · containerd/containerd

    Kubernetes-cni issue with 1.9.0 – no ip address available in range · Issue #57280 · kubernetes/kubernetes

  • 为阿里云 RDS MySQL 开启 SSL,并使用自签证书

    最近发现阿里云 99 计划的数据库,竟然包含香港地区,于是又冲动消费了。整了一个给 K3s 玩,试试它的 HA 模式。不过现有的节点很多都不在阿里云内网,需要开放数据库的公网访问才可以。开放数据库公网访问必然要开启 SSL 了,不然数据直接在公网上面明文传输十分危险。

    问题

    一开始我直接在阿里云 RDS 控制台上启用 SSL,使用默认的云端证书,然后先用 Grafana 去尝试连接,发现无法成功校验证书,报错:

    Error: ✗ failed to connect to database: tls: failed to verify certificate: x509: certificate relies on legacy Common Name field, use SANs instead

    猜测默认的云端证书只有在 Common Name 字段带上了数据库连接地址,而 Go 1.15 之后需要从 Subject Alternative Names 中进行校验,综合考虑后决定使用自签证书。

    自签证书

    平时 OpenSSL 用得不多,于是直接使唤 AI 干活:

    openssl genpkey -algorithm RSA -out ca-key.pem
    openssl req -new -x509 -key ca-key.pem -out ca-cert.pem -days 3650 -subj "/CN=MySQL CA"
    
    openssl genpkey -algorithm RSA -out server-key.pem
    openssl req -new -key server-key.pem -out server-req.pem -subj "/CN=rm-foo.mysql.rds.aliyuncs.com"
    openssl x509 -req -in server-req.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -days 3650 -extfile <(printf "subjectAltName=DNS:rm-foo.mysql.rds.aliyuncs.com")

    然后在 RDS 控制台上传生成的服务端证书就可以了。

    在 Grafana 上配置

    我们需要先将上面生成的 CA 证书先挂载到 Grafana 容器中,然后参考官方文档进行配置,使其可以经由 TLS 连接数据库。

    我的 Grafana 是使用官方的 Helm Chart 部署的,其提供了一个可以注入 ConfigMap 的配置项,因此我们先创建一个包含了 CA 的 ConfigMap:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      creationTimestamp: null
      name: grafana-database-tls-ca
      namespace: monitoring
    data:
      certificates.crt: |
        -----BEGIN CERTIFICATE-----
        -----END CERTIFICATE-----

    然后在 values.yaml 中配置挂载它:

    extraConfigmapMounts:
      - name: database-tls-ca
        mountPath: /etc/grafana/ssl/
        subPath: certificates.crt
        configMap: grafana-database-tls-ca
        readOnly: true

    这样的话,CA 就已经被挂载到 Grafana 容器中了。接下来我们需要配置 Grafana 以开启 TLS,同样,这里也是在 values.yaml 中配置就行。

    grafana.ini:
      database:
        type: mysql
        host: rm-foo.mysql.rds.aliyuncs.com
        ssl_mode: true
        ssl_sni: rm-foo.mysql.rds.aliyuncs.com
        server_cert_name: rm-foo.mysql.rds.aliyuncs.com
        ca_cert_path: /etc/grafana/ssl
        user: $__file{/etc/secrets/grafana-database/username}
        password: $__file{/etc/secrets/grafana-database/password}

    如果配置没有问题的话,此时执行更新之后应该就可以了。

    在 K3s 上配置

    同样,官方文档给出了配置项。我们需要先把刚才的 CA 证书复制到 K3s server 服务器上,然后修改启动脚本。

    curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--flannel-backend=wireguard-native --disable=servicelb --disable=traefik --disable=metrics-server" \
            sh -s - server \
            --datastore-endpoint="mysql://username:password@tcp(host:3306)/database" \
            --datastore-cafile="/usr/local/share/ca-certificates/mysql.crt" \
            --flannel-external-ip \
            --node-ip 1.2.3.4 \
            --kubelet-arg=node-ip=0.0.0.0

    因为配置变化,安装脚本会更新配置并重启 K3s。如果配置没有问题,K3s 会正常启动。

    后记

    强制指定用户使用加密连接

    如果全部的工作负载已经迁移至 TLS 连接,那么我们就可以配置数据库特定用户必须使用加密连接。

    ALTER USER k3s@'%' REQUIRE SSL;
    FLUSH PRIVILEGES;

    配置生效之后,我们可以重启工作负载进行验证。

    为什么不通过一些 workaround 来使用默认的云端证书

    为了行文的连贯性,我把这段放到了这里。你可能会想到几个问题:

    Q:为什么不直接 skip-verify?省得折腾半天。

    A:不安全,这不是我的风格。而且根据 K3s 文档,其至今仍然暂时无法跳过证书检查。虽然 K3s 的数据库读写垫片 kine 项目已经有人实现了 skip-verify 选项并且已经合入主干+发布,但是当下等待 K3s 支持还早,感兴趣的可以看下面的链接。

    k3s can’t utilize tls option with mysql external database · Issue #1093 · k3s-io/k3s · GitHub

    Add support for TLS skip verification by tuxillo · Pull Request #306 · k3s-io/kine · GitHub

    Q:为什么不使用 GODEBUG=x509ignoreCN=0 环境变量使其可以校验 CN 而不是 SANs?

    A:Go 从 1.15 开始校验 SANs 而不是 CN,从 1.17 开始将会移除这个选项,出于长远考虑我不会这么做。

    x509: certificate relies on legacy Common Name field, use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0 · Issue #775 · rancher/rke2 · GitHub

    引用

    Configure Grafana | Grafana documentation

    Cluster Datastore | K3s

    certificates – Provide subjectAltName to openssl directly on the command line – Information Security Stack Exchange

    How do I use SANs with openSSL instead of common name? – Stack Overflow

  • 使用 Docker Registry 自托管一个缓存镜像源

    部署

    由于是在一个 1C1G 的机器上部署,就不用 K3s 了,直接用 Docker Compose 拉起一个实例。官方文档有提供 docker-compose.yml,这里也给出一份示例:

    version: '3'
    
    services:
      registry-docker:
        image: registry:2
        restart: unless-stopped
        environment:
          REGISTRY_PROXY_REMOTEURL: https://registry-1.docker.io
          REGISTRY_PROXY_USERNAME: username
          REGISTRY_PROXY_PASSWORD: dckr_pat_value
          # REGISTRY_AUTH: htpasswd
          # REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
          # REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
          REGISTRY_STORAGE_DELETE_ENABLED: "true"
        ports:
          - 127.0.0.1:50000:5000
        volumes:
          - ./data/auth:/auth
          - ./data/docker:/var/lib/registry
    

    这里的账密可以提高拉取限频,但是根据官方文档,使用镜像的用户就可以读到该账号下的私有镜像了,最好是一个独立的账号。

    服务拉起来之后,Nginx 反代一下就可以使用了。

    拉取

    有两种方式可以使用,首先是最普遍且最优的做法,在 /etc/docker/daemon.json 中加入 registry-mirrors 选项。例如:

    {
      "registry-mirrors": [
        "https://<docker-registry-host>"
      ]
    }

    然后重启 Docker Engine 即可。

    不过此种方式不支持 HTTP Basic 身份验证,这也就意味着无法通过事先 docker login 的方式来拉取私有的镜像源。目前各镜像站通常的做法是使用泛域名,在域名中提供唯一身份信息,显然这种方式并不安全,只是对当下现状的妥协。

    这种情况应该在下一个版本的 Docker 中应该可以得到解决,在即将发布的 24.08/25.0 版本中,我们可以在 [24.0 backport] registry: allow mirror path prefix in config by thaJeztah · Pull Request #46944 · moby/moby (github.com) 中看到,可以支持填带路径的镜像源了,这就意味着可以在路径上实现类似的认证,因为 HTTPS 中路径是受保护的,这样的话就不会有问题了。

    另一种方式是手动拉取,这需要以 docker pull <docker-registry-host>/library/nginx:stable 的格式进行拉取。这种方式支持 HTTP Basic 认证。

    认证

    Docker Registry 上支持认证,可以参照上面的 docker-compose.yml 处理;也可以在反代上面认证,其官方文档给出了 Apache/Nginx 上面的配置示例,具体请参考 Authenticate proxy with nginx | CNCF Distribution

    引用

    Registry as a pull through cache | Docker Docs

    Docker daemon won’t start if a registry-mirror is configured in /etc/docker/daemon.json · Issue #36598 · moby/moby (github.com)

    registry: allow mirror path prefix in config · thaJeztah/docker@3d8f7d0 (github.com)

    Pull-through cache is not working for private registry: Challenge established with upstream · Issue #3081 · distribution/distribution (github.com)

    Implement Basic authentication to upstream registry in proxy mode by ArthurMelin · Pull Request #3256 · distribution/distribution (github.com)

    Private Docker registry in pull through cache mode return “invalid authorization credential” – Stack Overflow

    Private docker registry behind a subpath : r/docker (reddit.com)

    Private Docker registry in pull through cache mode return “invalid authorization credential” – Stack Overflow

  • Lens 安装 kube-state-metrics 超时

    使用 Lens 安装 kube-state-metrics 时发现,镜像是从 k8s.gcr.io/kube-state-metrics/kube-state-metrics:v2.0.0 拉取的,国内的 TKE 集群拉取会超时。可以直接修改 Deployment 的镜像为:ccr.ccs.tencentyun.com/tkeimages/kube-state-metrics:v2.0.0。

    也可以从 k8s-gcrio.azureedge.net/kube-state-metrics/kube-state-metrics:v2.0.0 拉取。

    如果只有单节点而且不想修改 Deployment 的话,可以在对应机器上拉取国内镜像,然后使用对应运行时的镜像工具修改镜像 Tag。以 containerd 为例:

    crictl pull ccr.ccs.tencentyun.com/tkeimages/kube-state-metrics:v2.0.0
    ctr -n k8s.io image tag ccr.ccs.tencentyun.com/tkeimages/kube-state-metrics:v2.0.0 k8s.gcr.io/kube-state-metrics/kube-state-metrics:v2.0.0

  • 修改 Kubernetes 默认 StorageClass

    今天部署一个应用的时候卡在新建 PVC,看到报错:

    Internal error occurred: 2 default StorageClasses were found

    编辑那个现在是默认,但是实际上不需要是默认的 sc,把:

    storageclass.kubernetes.io/is-default-class

    注解改为 false,或直接删除。

    引用

    https://kubernetes.io/docs/tasks/administer-cluster/change-default-storage-class/

  • 增加 Kubernetes CoreDNS Hosts 以自定义解析结果

    编辑 kube-system 中的 coredns 这个 ConfigMap,可以:

    kubectl edit configmap coredns -n kube-system

    在 Corefile 的:

    .:53 {
      ... ...
    }

    添加:

    hosts {
      127.0.0.1 localhost
      fallthrough
    }

    如果需要对单个 Pod 级别生效,可以设置 hostAliases。见:

    https://kubernetes.io/docs/tasks/network/customize-hosts-file-for-pods/#adding-additional-entries-with-hostaliases

    引用

    https://stackoverflow.com/a/65283959
    https://coredns.io/plugins/hosts/

    我还发现了什么好玩的

    由于不知道 Corefile 语法高亮应该用啥,于是看到了:

    https://coredns.io/2017/07/23/corefile-explained/

目录