k3s完全兼容k8s,我解释一下是为什么:
因为k3s的底层数据结构(写入etcd/mysql/sqlite/dsqlite数据库的格式),是完全照搬k8s的数据结构。api完全兼容。 对外表现相同,底层数据相同,只是实现方式不同(举个例子: 一个爆炒大虾,一个油焖虾)。
我认为 k3s/k8s数据结构的3个用途:
- 缓存从api中解析出来的参数,为了后面的处理逻辑更方便的去引用api的参数。
- 方便响应api时,用marshal() 去生成json/protobuf序列化的数据
- 方便写入数据库(etcd/mysql/sqlite)时,序列化为有序数据块
在k3s/k8s中,deploy、pod、service、Ingress、namespace、configmap等被成为资源。
yaml文件在定义一组(多组)资源的规格/约束条件的集合。
1 资源类型:
type TypeMeta struct {
// rest api操作的资源类型:deployment/pod/servce/ingress/ns/pv/pvc
Kind string `json:"kind,omitempty" protobuf:"bytes,1,opt,name=kind"`
// APIVersion defines the versioned schema of this representation of an object.
// Servers should convert recognized schemas to the latest internal value, and
// may reject unrecognized values.
APIVersion string `json:"apiVersion,omitempty" protobuf:"bytes,2,opt,name=apiVersion"`
}
2 资源元数据:
资源元数据:与api相关、与调度器相关、与数据库相关。 什么叫相关? 直白点说:就是被读写
type ObjectMeta struct {
// 在一个命名空间范围中,资源的名字(pod-https、pod-http、pod-web、sevice-reds、confiigmap-secrets-web)。 例如某个村里面(命名空间)不允许人重名,张三、李四
Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"`
// 在创建yaml文件时,可以指定资源名称、也可以不指定资源名称(不指定时则 用资源类型-随机字符拼接,例如pod-nx7jsda,service-hlayjk0a),此变量就是k3s/k8s生成的默认资源名称
GenerateName string `json:"generateName,omitempty" protobuf:"bytes,2,opt,name=generateName"`
// 命名空间名称,例如default、filecoin、ingress-nginx。在同一个命名空间内,所有资源可互相感知存在。 在不同命名空间中,资源之间不能直接感知到其它命名空间的资源。
Namespace string `json:"namespace,omitempty" protobuf:"bytes,3,opt,name=namespace"`
// url地址,client可以通过访问此地址,来只读到资源的内容。 对应另外一个命令是读写,kubectl edit pod pod-name
// k3s/k8s在1.21 release会删除此变量(因为有读写api、(历史原因存在的)只读api显得很鸡肋),无视它即可。
SelfLink string `json:"selfLink,omitempty" protobuf:"bytes,4,opt,name=selfLink"`
// k8s server在最终成功创建了资源后,会生成一个uuid给这资源,生成后,在资源的整个生命周期中不允许被修改。 (你可以理解为是身份证编号)
UID types.UID `json:"uid,omitempty" protobuf:"bytes,5,opt,name=uid,casttype=k8s.io/kubernetes/pkg/types.UID"`
// k3s/k8s 兼容多个api版本,即http/https rest api接口存在多个版本的路由,和多个版本对应的参数逻辑解析程序段
// apiVersion: v1
// apiVersion: v2
// apps/v1beta1
ResourceVersion string `json:"resourceVersion,omitempty" protobuf:"bytes,6,opt,name=resourceVersion"`
// 流水号
Generation int64 `json:"generation,omitempty" protobuf:"varint,7,opt,name=generation"`
// 资源被创建时的时间戳
CreationTimestamp Time `json:"creationTimestamp,omitempty" protobuf:"bytes,8,opt,name=creationTimestamp"`
// 资源被删除时的时间戳,例如kubectl delete pods pod-name 命令被执行到时的时间戳
DeletionTimestamp *Time `json:"deletionTimestamp,omitempty" protobuf:"bytes,9,opt,name=deletionTimestamp"`
// 资源被删除时的宽限(给资源发让其退出的信号,等待资源关闭相关的系统资源后退出)时间(单位:秒),超过宽限时间则k3s/k8s会主动杀死资源
DeletionGracePeriodSeconds *int64 `json:"deletionGracePeriodSeconds,omitempty" protobuf:"varint,10,opt,name=deletionGracePeriodSeconds"`
// 给资源打标签: kubectl label node cka-node disktype=gpu
// 查看资源标签: kubectl get node --show-labels
// 标签用途:用于更精细的去调度资源到指定的node,是k3/k8s为运维通讯提供的(管理/调度)扩展功能
Labels map[string]string `json:"labels,omitempty" protobuf:"bytes,11,rep,name=labels"`
// 注解:
//Annotations 允许在 Kubernetes 资源上附加任意的非标识性元数据,用来记录资源的一些属性。这些元数据主要是给工具或者库来提取信息,一般不会直接开放给用户。绝大多数基于 Kubernetes 的开源项目都不依赖于 DB,完全可以利用 Kubernetes 的能力,满足对 DB 的需求。对于需要持久化的数据,除了定义 CRD,另一种通用的做法就是将数据存储在 annotation 中。
//由于 annotation 的定位是 Kubernetes 资源上附加任意的非标识性元数据,除了在 key 上有跟 label key 完全一样的限制外,在 value 上没有任何限制:可长可短,可结构化可非结构化,可包含任意字符。
Annotations map[string]string `json:"annotations,omitempty" protobuf:"bytes,12,rep,name=annotations"`
// 包含足够的信息来让你确定一个对象,举个例子:你妈妈喊你吃饭时叫你小名:小张、狗子,你就知道是在叫你,而不用叫你的全名:张三丰、赵二狗
OwnerReferences []OwnerReference `json:"ownerReferences,omitempty" patchStrategy:"merge" patchMergeKey:"uid" protobuf:"bytes,13,rep,name=ownerReferences"`
// 资源在被删除之后,会写一个记录在这里切片中
Finalizers []string `json:"finalizers,omitempty" patchStrategy:"merge" protobuf:"bytes,14,rep,name=finalizers"`
// 资源属于的集群的名称。例如:易春雷老师(资源)是第二初级中学(集群名称)的优秀班主任,
ClusterName string `json:"clusterName,omitempty" protobuf:"bytes,15,opt,name=clusterName"`
//
ManagedFields []ManagedFieldsEntry `json:"managedFields,omitempty" protobuf:"bytes,17,rep,name=managedFields"`
}
type ManagedFieldsEntry struct {
// Manager is an identifier of the workflow managing these fields.
Manager string `json:"manager,omitempty" protobuf:"bytes,1,opt,name=manager"`
// Operation is the type of operation which lead to this ManagedFieldsEntry being created.
// The only valid values for this field are 'Apply' and 'Update'.
Operation ManagedFieldsOperationType `json:"operation,omitempty" protobuf:"bytes,2,opt,name=operation,casttype=ManagedFieldsOperationType"`
// APIVersion defines the version of this resource that this field set
// applies to. The format is "group/version" just like the top-level
// APIVersion field. It is necessary to track the version of a field
// set because it cannot be automatically converted.
APIVersion string `json:"apiVersion,omitempty" protobuf:"bytes,3,opt,name=apiVersion"`
// Time is timestamp of when these fields were set. It should always be empty if Operation is 'Apply'
// +optional
Time *Time `json:"time,omitempty" protobuf:"bytes,4,opt,name=time"`
// Fields is tombstoned to show why 5 is a reserved protobuf tag.
//Fields *Fields `json:"fields,omitempty" protobuf:"bytes,5,opt,name=fields,casttype=Fields"`
// FieldsType is the discriminator for the different fields format and version.
// There is currently only one possible value: "FieldsV1"
FieldsType string `json:"fieldsType,omitempty" protobuf:"bytes,6,opt,name=fieldsType"`
// FieldsV1 holds the first JSON version format as described in the "FieldsV1" type.
// +optional
FieldsV1 *FieldsV1 `json:"fieldsV1,omitempty" protobuf:"bytes,7,opt,name=fieldsV1"`
// Subresource is the name of the subresource used to update that object, or
// empty string if the object was updated through the main resource. The
// value of this field is used to distinguish between managers, even if they
// share the same name. For example, a status update will be distinct from a
// regular update using the same manager name.
// Note that the APIVersion field is not related to the Subresource field and
// it always corresponds to the version of the main resource.
Subresource string `json:"subresource,omitempty" protobuf:"bytes,8,opt,name=subresource"`
}
先写到这里,晚点补充其它数据结构。
3 服务:
type Service struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// 存放servince.yaml文件定义的内容,被解析后的值
Spec ServiceSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
// 服务/ingress的实时状态
Status ServiceStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}
type ServicePort struct {
// 服务对应的端口的(唯一)名字
Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"`
// The IP protocol for this port. Supports "TCP", "UDP", and "SCTP".
// Default is TCP.
// +default="TCP"
Protocol Protocol `json:"protocol,omitempty" protobuf:"bytes,2,opt,name=protocol,casttype=Protocol"`
// The application protocol for this port.
// This field follows standard Kubernetes label syntax.
// Un-prefixed names are reserved for IANA standard service names (as per
AppProtocol *string `json:"appProtocol,omitempty" protobuf:"bytes,6,opt,name=appProtocol"`
// The port that will be exposed by this service.
Port int32 `json:"port" protobuf:"varint,3,opt,name=port"`
// 服务访问pod的端口
TargetPort intstr.IntOrString `json:"targetPort,omitempty" protobuf:"bytes,4,opt,name=targetPort"`
// linux node 真实port
NodePort int32 `json:"nodePort,omitempty" protobuf:"varint,5,opt,name=nodePort"`
}
type ServiceSpec struct {
// 本服务暴露的端口列表
Ports []ServicePort `json:"ports,omitempty" patchStrategy:"merge" patchMergeKey:"port" protobuf:"bytes,1,rep,name=ports"`
// 服务选择器:一组标签,用于匹配符合标签的资源
Selector map[string]string `json:"selector,omitempty" protobuf:"bytes,2,rep,name=selector"`
// 随机ip地址(kubectl cli未指定的话),指定本服务的ip地址
ClusterIP string `json:"clusterIP,omitempty" protobuf:"bytes,3,opt,name=clusterIP"`
// 随机ip地址列表(kubectl cli未指定的话),指定本服务的ip(多个)地址
ClusterIPs []string `json:"clusterIPs,omitempty" protobuf:"bytes,18,opt,name=clusterIPs"`
// 服务被暴露的方式:ClusterIP/NodePort/LoadBalancer
Type ServiceType `json:"type,omitempty" protobuf:"bytes,4,opt,name=type,casttype=ServiceType"`
// externalIPs is a list of IP addresses for which nodes in the cluster
// will also accept traffic for this service. These IPs are not managed by
// Kubernetes. The user is responsible for ensuring that traffic arrives
// at a node with this IP. A common example is external load-balancers
// that are not part of the Kubernetes system.
// +optional
ExternalIPs []string `json:"externalIPs,omitempty" protobuf:"bytes,5,rep,name=externalIPs"`
// Supports "ClientIP" and "None". Used to maintain session affinity.
// Enable client IP based session affinity.
// Must be ClientIP or None.
// Defaults to None.
// More info: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies
// +optional
SessionAffinity ServiceAffinity `json:"sessionAffinity,omitempty" protobuf:"bytes,7,opt,name=sessionAffinity,casttype=ServiceAffinity"`
// Only applies to Service Type: LoadBalancer
// LoadBalancer will get created with the IP specified in this field.
// This feature depends on whether the underlying cloud-provider supports specifying
// the loadBalancerIP when a load balancer is created.
// This field will be ignored if the cloud-provider does not support the feature.
// +optional
LoadBalancerIP string `json:"loadBalancerIP,omitempty" protobuf:"bytes,8,opt,name=loadBalancerIP"`
// If specified and supported by the platform, this will restrict traffic through the cloud-provider
// load-balancer will be restricted to the specified client IPs. This field will be ignored if the
// cloud-provider does not support the feature."
// More info: https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/
// +optional
LoadBalancerSourceRanges []string `json:"loadBalancerSourceRanges,omitempty" protobuf:"bytes,9,opt,name=loadBalancerSourceRanges"`
// externalName is the external reference that discovery mechanisms will
// return as an alias for this service (e.g. a DNS CNAME record). No
// proxying will be involved. Must be a lowercase RFC-1123 hostname
// (https://tools.ietf.org/html/rfc1123) and requires `type` to be "ExternalName".
// +optional
ExternalName string `json:"externalName,omitempty" protobuf:"bytes,10,opt,name=externalName"`
// externalTrafficPolicy denotes if this Service desires to route external
// traffic to node-local or cluster-wide endpoints. "Local" preserves the
// client source IP and avoids a second hop for LoadBalancer and Nodeport
// type services, but risks potentially imbalanced traffic spreading.
// "Cluster" obscures the client source IP and may cause a second hop to
// another node, but should have good overall load-spreading.
// +optional
ExternalTrafficPolicy ServiceExternalTrafficPolicyType `json:"externalTrafficPolicy,omitempty" protobuf:"bytes,11,opt,name=externalTrafficPolicy"`
// 服务监控侦测(节点)端口,只在LoadBalancer / externalTrafficPolicy 模式时有效
HealthCheckNodePort int32 `json:"healthCheckNodePort,omitempty" protobuf:"bytes,12,opt,name=healthCheckNodePort"`
// publishNotReadyAddresses indicates that any agent which deals with endpoints for this
// Service should disregard any indications of ready/not-ready.
// The primary use case for setting this field is for a StatefulSet's Headless Service to
// propagate SRV DNS records for its Pods for the purpose of peer discovery.
// The Kubernetes controllers that generate Endpoints and EndpointSlice resources for
// Services interpret this to mean that all endpoints are considered "ready" even if the
// Pods themselves are not. Agents which consume only Kubernetes generated endpoints
// through the Endpoints or EndpointSlice resources can safely assume this behavior.
// +optional
PublishNotReadyAddresses bool `json:"publishNotReadyAddresses,omitempty" protobuf:"varint,13,opt,name=publishNotReadyAddresses"`
// sessionAffinityConfig contains the configurations of session affinity.
// +optional
SessionAffinityConfig *SessionAffinityConfig `json:"sessionAffinityConfig,omitempty" protobuf:"bytes,14,opt,name=sessionAffinityConfig"`
// TopologyKeys is tombstoned to show why 16 is reserved protobuf tag.
//TopologyKeys []string `json:"topologyKeys,omitempty" protobuf:"bytes,16,opt,name=topologyKeys"`
// IPFamily is tombstoned to show why 15 is a reserved protobuf tag.
// IPFamily *IPFamily `json:"ipFamily,omitempty" protobuf:"bytes,15,opt,name=ipFamily,Configcasttype=IPFamily"`
// IPFamilies is a list of IP families (e.g. IPv4, IPv6) assigned to this
// service. This field is usually assigned automatically based on cluster
// configuration and the ipFamilyPolicy field. If this field is specified
// manually, the requested family is available in the cluster,
// and ipFamilyPolicy allows it, it will be used; otherwise creation of
// the service will fail. This field is conditionally mutable: it allows
// for adding or removing a secondary IP family, but it does not allow
// changing the primary IP family of the Service. Valid values are "IPv4"
// and "IPv6". This field only applies to Services of types ClusterIP,
// NodePort, and LoadBalancer, and does apply to "headless" services.
// This field will be wiped when updating a Service to type ExternalName.
//
// This field may hold a maximum of two entries (dual-stack families, in
// either order). These families must correspond to the values of the
// clusterIPs field, if specified. Both clusterIPs and ipFamilies are
// governed by the ipFamilyPolicy field.
// +listType=atomic
// +optional
IPFamilies []IPFamily `json:"ipFamilies,omitempty" protobuf:"bytes,19,opt,name=ipFamilies,casttype=IPFamily"`
// IPFamilyPolicy represents the dual-stack-ness requested or required by
// this Service. If there is no value provided, then this field will be set
// to SingleStack. Services can be "SingleStack" (a single IP family),
// "PreferDualStack" (two IP families on dual-stack configured clusters or
// a single IP family on single-stack clusters), or "RequireDualStack"
// (two IP families on dual-stack configured clusters, otherwise fail). The
// ipFamilies and clusterIPs fields depend on the value of this field. This
// field will be wiped when updating a service to type ExternalName.
// +optional
IPFamilyPolicy *IPFamilyPolicyType `json:"ipFamilyPolicy,omitempty" protobuf:"bytes,17,opt,name=ipFamilyPolicy,casttype=IPFamilyPolicyType"`
// allocateLoadBalancerNodePorts defines if NodePorts will be automatically
// allocated for services with type LoadBalancer. Default is "true". It
// may be set to "false" if the cluster load-balancer does not rely on
// NodePorts. If the caller requests specific NodePorts (by specifying a
// value), those requests will be respected, regardless of this field.
// This field may only be set for services with type LoadBalancer and will
// be cleared if the type is changed to any other type.
// This field is beta-level and is only honored by servers that enable the ServiceLBNodePortControl feature.
// +featureGate=ServiceLBNodePortControl
// +optional
AllocateLoadBalancerNodePorts *bool `json:"allocateLoadBalancerNodePorts,omitempty" protobuf:"bytes,20,opt,name=allocateLoadBalancerNodePorts"`
// loadBalancerClass is the class of the load balancer implementation this Service belongs to.
// If specified, the value of this field must be a label-style identifier, with an optional prefix,
// e.g. "internal-vip" or "example.com/internal-vip". Unprefixed names are reserved for end-users.
// This field can only be set when the Service type is 'LoadBalancer'. If not set, the default load
// balancer implementation is used, today this is typically done through the cloud provider integration,
// but should apply for any default implementation. If set, it is assumed that a load balancer
// implementation is watching for Services with a matching class. Any default load balancer
// implementation (e.g. cloud providers) should ignore Services that set this field.
// This field can only be set when creating or updating a Service to type 'LoadBalancer'.
// Once set, it can not be changed. This field will be wiped when a service is updated to a non 'LoadBalancer' type.
// +featureGate=LoadBalancerClass
// +optional
LoadBalancerClass *string `json:"loadBalancerClass,omitempty" protobuf:"bytes,21,opt,name=loadBalancerClass"`
// InternalTrafficPolicy specifies if the cluster internal traffic
// should be routed to all endpoints or node-local endpoints only.
// "Cluster" routes internal traffic to a Service to all endpoints.
// "Local" routes traffic to node-local endpoints only, traffic is
// dropped if no node-local endpoints are ready.
// The default value is "Cluster".
// +featureGate=ServiceInternalTrafficPolicy
// +optional
InternalTrafficPolicy *ServiceInternalTrafficPolicyType `json:"internalTrafficPolicy,omitempty" protobuf:"bytes,22,opt,name=internalTrafficPolicy"`
}
type LoadBalancerStatus struct {
// ingress-nginx是组路由规则,这里是路由规则列表
Ingress []LoadBalancerIngress `json:"ingress,omitempty" protobuf:"bytes,1,rep,name=ingress"`
}
type ServiceStatus struct {
// ingress 状态
LoadBalancer LoadBalancerStatus `json:"loadBalancer,omitempty" protobuf:"bytes,1,opt,name=loadBalancer"`
// Current service state
// +optional
// +patchMergeKey=type
// +patchStrategy=merge
// +listType=map
// +listMapKey=type
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,2,rep,name=conditions"`
}
type LoadBalancerIngress struct {
// IP is set for load-balancer ingress points that are IP based
// (typically GCE or OpenStack load-balancers)
// +optional
IP string `json:"ip,omitempty" protobuf:"bytes,1,opt,name=ip"`
// Hostname is set for load-balancer ingress points that are DNS based
// (typically AWS load-balancers)
// +optional
Hostname string `json:"hostname,omitempty" protobuf:"bytes,2,opt,name=hostname"`
// Ports is a list of records of service ports
// If used, every port defined in the service should have an entry in it
// +listType=atomic
// +optional
Ports []PortStatus `json:"ports,omitempty" protobuf:"bytes,4,rep,name=ports"`
}
type PortStatus struct {
// Port is the port number of the service port of which status is recorded here
Port int32 `json:"port" protobuf:"varint,1,opt,name=port"`
// Protocol is the protocol of the service port of which status is recorded here
// The supported values are: "TCP", "UDP", "SCTP"
Protocol Protocol `json:"protocol" protobuf:"bytes,2,opt,name=protocol,casttype=Protocol"`
Error *string `json:"error,omitempty" protobuf:"bytes,3,opt,name=error"`
}
4 service/ingress暴露端口映射关系:
5 挂载容器运行时:
“/var/run/netns”, “/run/containerd”, “/run/xtables.lock” 是三个linux系统内核特殊目录,用于与内核虚拟化接口进行交互
6 port、nodeport、targetport的关系如下:
- port: 服务(被k8s集群以外的组件)访问的端口
- targetPort: 容器内部通讯端口
- nodePort:: k8s外部的组件调用pod的一种方式叫NodePort,另外一种方式是LoadBalaner