1 Kubectl
custom-columns
kubectl get application -A -o "custom-columns=PRODUCT:.metadata.labels.infra\.tce\.io/oam-product"
通过curl命令访问k8s apiserver
有时候没有kubectl程序, 需要用curl来获取
TOKEN=$(kubectl get secrets -o jsonpath="{.items[?(@.metadata.annotations['kubernetes\.io/service-account\.name']=='default')].data.token}"|base64 -d)
APISERVER=$(kubectl config view -o jsonpath="{.clusters[?(@.name==\"$CLUSTER_NAME\")].cluster.server}")
curl -X GET $APISERVER/api --header "Authorization: Bearer $TOKEN" --insecure
在pod内访问k8s apiserver时, TOKEN位于 var/run/secrets/kubernetes.io/serviceaccount/token, APISERVER就是 KUBERNETES_SERVICE_HOST:KUBERNETES_SERVICE_PORT, 注意要加https:/
通过raw url来watch某个resource的事件
kubectl proxy &
curl -L -s -X GET -H "Content-Type: application/json" -H "Accept: application/json, */*" 127.0.0.1:8001/apis/k8s.test.io/v1alpha1/watch/namespaces/default/greetings
通过raw url来patch status
curl -k -s -X PATCH -H "Accept: application/json, */*" -H "Content-Type: application/merge-patch+json" 127.0.0.1:8001/apis/k8s.test.io/v1alpha1/namespaces/default/greetings/demo/status --data '{"status":{"ready":true}}'
获取某个obj的event
kubectl get event --namespace abc-namespace --field-selector involvedObject.name=my-pod-zl6m6
直接指定url查询
kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/nginx_vts_server_requests_per_second"
kubectl apply
https://kubernetes.io/zh/docs/tasks/manage-kubernetes-objects/declarative-config/
kubectl apply的时候, 会参考对象的 kubectl.kubernetes.io/last-applied-configuration的值, 并且仅对上次 apply的值进行修改. 例如某字段, 创建时通过kubectl apply创建, 那下次 apply时, 不管是修改还是删除, 都会修改该字段. 而如果某字段不是kubectl apply创建, 那下次kubectl apply时, 如果apply的内容不包含这个字段, 那么不会修改该字段的值
rollout
restart
kubectl rollout restart的原理是为deployment的.Spec.Template.ObjectMeta.Annotations加上注解kubectl.kubernetes.io/restartedAt
进而触发deployment的自动重建pod的机制
2 Service
通过kubectl proxy在集群外访问service
参考: https://kubectl.docs.kubernetes.io/pages/container_debugging/proxying_traffic_to_services.html
例如:
curl "localhost:8099/api/v1/namespaces/tke/services/https:tke-registry-api:443/proxy/apis/registry.tkestack.io/v1/namespaces"
访问的是tke namespace下的tke-registry-api这个service, 使用https协议和443端口, URL为/apis/registry.tkestack.io/v1/namespaces
3 约束
长度字符约束
- Name: 长度<=253, [a-z0-9.-], 数字字母结尾及开头, 且.后面那一段也必须以数字字母结尾及开头, 例如a.a-a合法, 但是a.-a不合法.
- Label Key: 长度<=63, [a-z0-9-], 数字字母开头及结尾. Key可以有一个域名作为前缀, 域名最长可以253字符
- Label value: 长度<=63, [a-zA-Z0-9.-_], 数字字母结尾及开头.
4 Pod
驱逐单个Pod
see:
https://kubernetes.io/zh/docs/tasks/administer-cluster/safely-drain-node/
curl -v -H 'Content-type: application/json' http://127.0.0.1:8080/api/v1/namespaces/default/pods/quux/eviction -d @eviction.json
{
"apiVersion": "policy/v1beta1",
"kind": "Eviction",
"metadata": {
"name": "quux",
"namespace": "default"
}
}
注意URL里的名字/namespace要和json里的名字/namespace对应上
5 operator
为crd增加自定义输出
增加注释: +//+kubebuilder:printcolumn:JSONPath=".status.status",name=Status,type=integer
6 GVK&GVR
例如一个daemonset:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
apps就是Group, v1就是Version, DaemonSet就是Kind, 加起来就是GVK
GVR则是GVK对应的url, 用于发送到apiserver. 通过REST Mapping完成GVK和GVR的映射
7 dynamic client
通过CRD的定义可以生成针对这个类型的一个clientset, 调用这个clientset可 以方便的处理CR的CRUD. 但是这也意味着使用方需要import生成的代码, 如果某 个需求是通用的调用一些没有提前知道的资源的CRUD就无法实现了, 这时候就需 要dynamic client.
dynamic client在使用时需要指定GVR, 得到的资源以unstructure.Unstructure 表示, 所有的读取编辑操作需要调用unstructure库来完成
dynamic client内部其实包装了rest client, 最终是调用rest client来进行http请求
// c.client是dynamic client
// c.client.client是rest client
result := c.client.client.
Post().
AbsPath(append(c.makeURLSegments(name), subresources...)...).
Body(outBytes).
SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).
Do(ctx)
controller-runtime中的client
controller-runtime提供的client封装了unstructuredClient和typedClient, 其本质都是调用client-go的RestClient
当上层业务通过以下代码读数据时:
// Get returns the flow instance with given name.
func (nc *flowController) Get(namespace, name string) (*nonv1.TFlow, error) {
key := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var flow nonv1.TFlow
if err := nc.client.Get(context.TODO(), key, &flow); err != nil {
return nil, err
}
return &flow, nil
}
controller-runtime的client会检查对象时unstructure还是typed, 然后调用不同的client
// Get implements client.Client
func (c *client) Get(ctx context.Context, key ObjectKey, obj runtime.Object) error {
_, ok := obj.(*unstructured.Unstructured)
if ok {
return c.unstructuredClient.Get(ctx, key, obj)
}
return c.typedClient.Get(ctx, key, obj)
}
但是这两个client最终都是调用rest client, 只不过如果obj是明确了类型, 可以通过提前注册的scheme查到gvk, 否则就得用使用方自行提供gvk
func init() {
_ = nonv1.AddToScheme(scheme)
}
func New(){
// 创建controller-runtime中的client时需要提供Scheme, 其中就包含了GVK与某个类型的映射关系
cli, err := client.New(config, client.Options{Scheme: scheme})
}