Kubernetes 系列 - 1. 本地调试环境准备(Windows+GoLand)

184 阅读4分钟

1. 环境准备

本文档基于以下环境:

  • System:Windows;
  • IDE:GoLand;

1.1 apiserver

1.1.1 etcd

  1. 下载 etcd:github.com/etcd-io/etc…

  2. 解压;

  3. 启动 etcd:.\etcd.exe

    image.png

  4. 在启动参数中指定 etcd

    --etcd-servers=127.0.0.1:2379
    

1.1.2 证书

需要的文件 ext.conf:

[ca]
basicConstraints=critical,CA:true
extendedKeyUsage=serverAuth,clientAuth
​
[apiserver]
subjectAltName=DNS:kubernetes,DNS:kubernetes.default,DNS:kubernetes.default.svc,DNS:kubernetes.default.svc.cluster,DNS:kubernetes.default.svc.cluster.local,IP:127.0.0.1,IP:10.96.0.1,IP:192.168.0.1

所有命令如下:

# ca
openssl genrsa -out ca.key 2048
openssl req -new -key ca.key -out ca.csr -subj "/CN=Kubernetes CA" -addext "basicConstraints=critical,CA:TRUE"
openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt -days 365 -extfile ext.conf -extensions ca
​
# apiserver
openssl genrsa -out apiserver.key 2048
openssl req -new -key apiserver.key -out apiserver.csr -subj "/CN=kubernetes"
openssl x509 -req -in apiserver.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out apiserver.crt -days 365 -extfile ext.conf -extensions apiserver
​
# kubelet
openssl genrsa -out kubelet.key 2048
openssl req -new -key kubelet.key -out kubelet.csr -subj "/CN=node1" -addext "subjectAltName = IP:10.0.0.2,DNS:node1"
openssl x509 -req -in kubelet.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out kubelet.crt -days 365
​
# service-account
openssl genrsa -out service-account.key 2048
openssl rsa -in service-account.key -pubout -out service-account.pub

接下来进行说明。

  1. 安装 openssl

  2. 生成 CA 证书和私钥

    1. 生成 CA 私钥

      openssl genrsa -out ca.key 2048
      

      这将生成一个 2048 位的 RSA 私钥,保存为 ca.key 文件。

    2. 生成 CA 证书签名请求(CSR)

      openssl req -new -key ca.key -out ca.csr -subj "/CN=Kubernetes CA"
      

      这里 -subj 参数指定了证书的主题,CN 是证书的通用名称,你可以根据需要修改。

    3. 自签名 CA 证书

      创建 extension 文件,写入以下信息:

      [ca]
      basicConstraints=critical,CA:true
      extendedKeyUsage=serverAuth,clientAuth
      ​
      [apiserver]
      subjectAltName=DNS:kubernetes,DNS:kubernetes.default,DNS:kubernetes.default.svc,DNS:kubernetes.default.svc.cluster,DNS:kubernetes.default.svc.cluster.local,IP:127.0.0.1,IP:10.96.0.1,IP:192.168.0.1
      

      其中 ca 项是 ca 证书会用到的,主要表明是一个 ca 证书,apiserver 项是后面 apiserver 会用到的,要注意的是 192.168.0.1 是apiserver的访问地址。

      使用 CA 私钥对 CA 证书签名请求进行签名,生成一个有效期为 365 天的 CA 证书 ca.crt,并添加 ca extension:

      openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt -days 365 -extfile ext.conf -extensions ca
      
  3. 生成 apiserver 证书和私钥

    1. 生成 apiserver 私钥

      openssl genrsa -out apiserver.key 2048
      
    2. 生成 apiserver 证书签名请求(CSR)

      openssl req -new -key apiserver.key -out apiserver.csr -subj "/CN=kubernetes"
      

      这里 -subj 参数指定了证书的主题,CN 是证书的通用名称。-addext 参数用于添加扩展名,指定 apiserver 的 DNS 名称和 IP 地址。你需要根据实际情况替换 10.96.0.1 为你的 apiserver 服务的 IP 地址。

    3. 使用 CA 证书签名 apiserver 证书

      openssl x509 -req -in apiserver.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out apiserver.crt -days 365 -extfile ext.conf -extensions apiserver
      

      这将使用 CA 证书和私钥对 apiserver 的证书签名请求进行签名,生成一个有效期为 365 天的 apiserver 证书 apiserver.crt

  4. 生成 service-account 验证文件

    1. 生成私钥文件

      openssl genrsa -out service-account.key 2048
      
    2. 生成公钥文件

      openssl rsa -in service-account.key -pubout -out service-account.pub
      
  5. 生成 kubectl 证书

    为后续 curl 命令生成需要的证书,和 apiserver 几乎一致(不想创建的话,后面直接使用 apiserver 的证书):

    openssl genrsa -out kubelet.key 2048
    openssl req -new -key kubelet.key -out kubelet.csr -subj "/CN=node1" -addext "subjectAltName = IP:10.0.0.2,DNS:node1"
    openssl x509 -req -in kubelet.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out kubelet.crt -days 365
    
  6. 验证证书

    你可以使用以下命令验证生成的证书:

    openssl x509 -in apiserver.crt -text -noout
    

    这将显示 apiserver 证书的详细信息,包括主题、颁发者、有效期和扩展名等。

  7. 配置 kube-apiserver

    在 apiserver 的启动参数中指定证书和私钥的路径,例如:

    --tls-cert-file=${your_path}/apiserver.crt
    --tls-private-key-file=${your_path}/apiserver.key
    --client-ca-file=${your_path}/ca.crt
    --service-account-issuer=https://kubernetes.default.svc.cluster.local
    --api-audiences=https://kubernetes.default.svc.cluster.local
    --service-account-signing-key-file=${your_path}/service-account.key
    --service-account-key-file=${your_path}/service-account.pub
    

    GoLand 配置位置为:

    image.png

1.1.3 验证

  1. 启动 etcd 后 再启动 apiserver;

  2. 调用接口:

    curl --cacert ./ca.crt --cert ./kubelet.crt --key ./kubelet.key "https://192.168.0.1:6443/api/v1/pods"
    

    结果为:

    image.png

1.1.4 问题记录

  1. windows 的 curl 命令不是平常理解上的 curl 命令,是 Invoke-WebRequest 的别名。

    取消别名,下载 curl 命令(推荐使用 scoop)。

  2. curl: (58) schannel: Failed to import cert file .\kubelet.crt, last error is 0x80092002

    curl 版本有问题(curl 8.9.1 (Windows)),删除系统的curl(C:\Windows\System32),使用scoop重新安装(8.11.1 (x86_64-w64-mingw32))。

  3. 访问 apiserver 时返回码为401。

    在生成 openssla csr 的时候使用 -addext 参数添加 extension,但实际生成的 ca 证书没有 basicConstraints=critical,CA:true 这一项,导致报错:invalid signature: parent certificate cannot sign this kind of certificate " while trying to verify candidate authority certificate "Kubernetes CA" ",最后通过在生成 crt 的时候使用 -extfile 添加extension。

    该逻辑代码具体位置为:go1.23.0/src/crypto/x509/parser.go#processExtensions

    func processExtensions(out *Certificate) error {
        var err error
        for _, e := range out.Extensions {
            unhandled := falseif len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 {
                switch e.Id[3] {
                ...
                case 19:
                    out.IsCA, out.MaxPathLen, err = parseBasicConstraintsExtension(e.Value)
                    if err != nil {
                        return err
                    }
                    out.BasicConstraintsValid = true
                    out.MaxPathLenZero = out.MaxPathLen == 0
                ...
                }
            } 
            ...
        }
    ​
        return nil
    }
    

    在添加了 basicConstraints=critical,CA:true 的 extension 之后会在证书的 IsCA 置为 true,后续验证客户端证书的签发信息的时候会用到,若 ca 证书的 IsCA 为 false 则会返回 401。