01. apiserver 启动参数和调试准备

01. apiserver 启动参数和调试准备

apiserver 的入口:

func main() {
	command := app.NewAPIServerCommand()
	code := cli.Run(command)
	os.Exit(code)
}

命令行工具的功能是使用的 github.com/spf13/cobra 库,不要陷入细节,直接跳到 app.NewAPIServerCommand() 方法。

首先会初始化默认的启动参数,得到 *ServerRunOptions 类型的 s 变量:

s := options.NewServerRunOptions()

打个断点感受下 s 的默认值:

Untitled

其中各个参数的介绍可以看:https://kubernetes.io/zh-cn/docs/reference/command-line-tools-reference/kube-apiserver/

得到 s 参数后,还要对其进行一系列的处理,才可以使用:

// 设置默认参数选项
completedOptions, err := Complete(s)
if err != nil {
	return err
}

设置完后,还需要对参数进行合法性校验:

// 参数选项的校验
if errs := completedOptions.Validate(); len(errs) != 0 {
	return utilerrors.NewAggregate(errs)
}

在这里,如果参数不合法就会校验失败,errs 会返回具体的错误:

Untitled

为了让 apiserver 正常启动,需要设置 etcd 的参数配置(这里为了专注于 k8s 自身组件,etcd 就搭建了一个本地单机版,并且没有使用 tls 认证):

--etcd-servers=http://127.0.0.1:2379

而 apiserver 的 tls 证书配置,可以用 easyrsa 来生成:

curl -LO https://dl.k8s.io/easy-rsa/easy-rsa.tar.gz
tar xzf easy-rsa.tar.gz
cd easy-rsa-master/easyrsa3
./easyrsa init-pki
export MASTER_IP=127.0.0.1
export MASTER_CLUSTER_IP=127.0.0.1
./easyrsa --batch "--req-cn=${MASTER_IP}@`date +%s`" build-ca nopass
./easyrsa --subject-alt-name="IP:${MASTER_IP},"\
"IP:${MASTER_CLUSTER_IP},"\
"DNS:kubernetes,"\
"DNS:kubernetes.default,"\
"DNS:kubernetes.default.svc,"\
"DNS:kubernetes.default.svc.cluster,"\
"DNS:kubernetes.default.svc.cluster.local" \
--days=10000 \
build-server-full server nopass

将生成的证书( pki/ca.crtpki/issued/server.crt 和 pki/private/server.key)拷贝到自定义目录(例如:cert),并添加到 apiserver 的启动参数中:

--client-ca-file=cert/ca.crt
--tls-cert-file=cert/server.crt
--tls-private-key-file=cert/server.key

另外 pod 访问 kube-apiserver 还需要用到 service account 证书(pki/private/ca.key),需要指定服务帐号令牌颁发者 :

--service-account-issuer=api
--service-account-key-file=cert/ca.crt
--service-account-signing-key-file=cert/ca.key

总结,启动所需要的基本参数:

--etcd-servers=http://127.0.0.1:2379 --client-ca-file=cert/ca.crt --tls-cert-file=cert/server.crt --tls-private-key-file=cert/server.key --service-account-issuer=api --service-account-key-file=cert/ca.crt --service-account-signing-key-file=cert/ca.key

此时,cert 目录有以下证书文件(包括 ca 证书、服务端证书):

Untitled

apiserver 启动成功后,可以直接使用 curl 充当一个客户端调用 apiserver 的接口,但是得先为客户端创建客户端证书:

# 生成客户端私钥
openssl genrsa -out cert/client.key 2048
# 生成证书签名请求(CSR)
openssl req -new -key cert/client.key -out cert/client.csr -subj "/CN=<client-name>"
# 使用 kube-apiserver 的 CA 签署 CSR,生成客户端证书
openssl x509 -req -in cert/client.csr -CA cert/ca.crt -CAkey cert/ca.key -CAcreateserial -out cert/client.crt -days 365

Untitled

有了客户端证书,就可以调用 apiserver 接口了:

$ curl --cacert cert/ca.crt --cert cert/client.crt --key cert/client.key https://127.0.0.1:6443/version
{
  "major": "",
  "minor": "",
  "gitVersion": "v0.0.0-master+$Format:%H$",
  "gitCommit": "$Format:%H$",
  "gitTreeState": "",
  "buildDate": "1970-01-01T00:00:00Z",
  "goVersion": "go1.20.3",
  "compiler": "gc",
  "platform": "linux/amd64"
}

对于 kubectl 的使用,也同样需要使用客户端证书:

# 添加新集群(apiserver地址)
kubectl config set-cluster devk8s --server=https://127.0.0.1:6443 --certificate-authority=cert/ca.crt
# 添加用户(客户端证书)
kubectl config set-credentials devk8s --client-certificate=cert/client.crt --client-key=cert/client.key
# 添加上下文(绑定集群和用户)
kubectl config set-context devk8s --user=devk8s --cluster=devk8s
# 切换当前上下文
kubectl config use-context devk8s

验证 kubectl :


$ kubectl get ns
NAME              STATUS   AGE
default           Active   2d6h
kube-node-lease   Active   2d6h
kube-public       Active   2d6h
kube-system       Active   2d6h

创建一个 pod :

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80

如果遇到 pods "nginx" is forbidden: error looking up service account defau lt/default: serviceaccount "default" not found 错误,意味着还没有默认的 serviceaccount ,则先执行:

kubectl create sa default

创建 pod 后观察(控制平面组件未全部启动,处于 Pending 状态为正常现象):

$ kubectl get pod
NAME    READY   STATUS    RESTARTS   AGE
nginx   0/1     Pending   0          13s

当然,有了 kubectl ,可以直接使用 proxy 模式转发 apiserver 的接口:

kubectl proxy --port=8080

apiserver 的 API 使用了 openapi 规范,暴露出了 /openapi/v2 接口,所以如果有需要,可以自己搭建一个 swagger-ui 服务导入该接口地址进行调试。

Untitled

此时,etcd 存储的数据如下(使用 ETCD Keeper 可视化展示):

Untitled

至此,先告一段落,现在 apiserver 已经成功启动,为了后续方便调试 apiserver ,kubectl 工具,etcd 数据展示也已准备好。

微信公众号

更多内容请关注微信公众号:gopher云原生