Skip to content


k8s_安装9_ingress-nginx

九、 ingress-nginx

部署Ingress控制器

部署方式

Ingress控制器可以通过三种方式部署以接入外部请求流量。

第一种方式 Deployment+NodePort模式的Service

通过Deployment控制器管理Ingress控制器的Pod资源,通过NodePort或LoadBalancer类型的Service对象为其接入集群外部的请求流量,所有这种方式在定义一个Ingress控制器时必须在其前端定义一个专用的Service资源.
访问流量先通过nodeport进入到node节点,经iptables (svc) 转发至ingress-controller容器,再根据rule转发至后端各业务的容器中。

同用deployment模式部署ingress-controller,并创建对应的service,但是type为NodePort。这样,ingress就会暴露在集群节点ip的特定端口上。由于nodeport暴露的端口是随机端口,一般会在前面再搭建一套负载均衡器来转发请求。该方式一般用于宿主机是相对固定的环境ip地址不变的场景。
NodePort方式暴露ingress虽然简单方便,但是NodePort多了一层NAT,在请求量级很大时可能对性能会有一定影响。
流量先经过DNS域名解析,然后到达LB,然后流量经过ingress做一次负载分发到service,最后再由service做一次负载分发到对应的pod中

固定nodePort后,LB端指向nodeip+nodeport 任意一个都可以,如果当流量进来负载到某个node上的时候因为Ingress Controller的pod不在这个node上,会走这个node的kube-proxy转发到Ingress Controller的pod上,多转发了一次。nginx接收到的http请求中的source ip将会被转换为接受该请求的node节点的ip,而非真正的client端ip

Deployment 部署的副本 Pod 会分布在各个 Node 上,每个 Node 都可能运行好几个副本,replicas数量(不能大于node节点数) + nodeSeletor / podantifinity。DaemonSet 的不同之处在于:每个 Node 上最多只能运行一个副本。

nodeport优点:一个集群可以部署几个就可以了,你可以一组service对应一个ingress,这样只需要每组service自己维护自己的ingress中NGINX配置,每个ingress之间互不影响,各reload自己的配置,缺点是效率低。如果你使用hostnetwork方式,要么维护所有node上NGINX的配置。

第二种方式 DaemonSet+HostNetwork+nodeSelector

通过DaemonSet控制器确保集群的所有或部分工作节点中每个节点上只运行Ingress控制器的一个Pod资源,并配置这类Pod对象以HostPort或HostNetwork的方式在当前节点接入外部流量。
每个节点都创建一个ingress-controller的容器,容器的网络模式设为hostNetwork。访问请求通过80/443端口将直接进入到pod-nginx中。而后nginx根据ingress规则再将流量转发到对应的web应用容器中。

用DaemonSet结合nodeselector来部署ingress-controller到特定的node上,然后使用HostNetwork直接把该pod与宿主机node的网络打通,直接使用宿主机的80/433端口就能访问服务。这时,ingress-controller所在的node机器就很类似传统架构的边缘节点,比如机房入口的nginx服务器。该方式整个请求链路最简单,性能相对NodePort模式更好。缺点是由于直接利用宿主机节点的网络和端口,一个node只能部署一个ingress-controller pod。 比较适合大并发的生产环境使用。

不创建nginx svc,效率最高(不使用nodeport的方式进行暴露)。如果我们使用Nodeport的方式,流量是NodeIP->svc->ingress-controller(pod)这样的话会多走一层svc层,不管svc层是使用iptables还是lvs都会降低效率。如果使用hostNetwork的方式就是直接走Node节点的主机网络,唯一要注意的是hostNetwork下pod会继承宿主机的网络协议,也就是使用了主机的dns,会导致svc的请求直接走宿主机的上到公网的dns服务器而非集群里的dns server,需要设置pod的dnsPolicy: ClusterFirstWithHostNet即可解决

写入proxy 配置文件如 nginx.conf 的不是backend service的地址,而是backend service 的 pod 的地址,避免在 service 在增加一层负载均衡转发

hostNetwork需要占用物理机的80和443端口,80和443端口只能在绑定了的node上访问nodeip+80,没绑定的可以用nodeip+nodeport访问

这种方式可能会存在node间无法通信和集群内域名解析的问题
可以布署多套ingress,区分内外网访问,对业务进行拆分壁免reload影响

第三种方式 Deployment+LoadBalancer 模式的 Service

如果要把ingress部署在公有云,那用这种方式比较合适。用Deployment部署ingress-controller,创建一个 type为 LoadBalancer 的 service 关联这组 pod。大部分公有云,都会为 LoadBalancer 的 service 自动创建一个负载均衡器,通常还绑定了公网地址。 只要把域名解析指向该地址,就实现了集群服务的对外暴露

ingres-nginx

k8s社区的ingres-nginx https://github.com/kubernetes/ingress-nginx  
Ingress参考文档:https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/

kubectl get cs  

部署配置Ingress  
ingress-nginx v1.9.3
k8s supported version 1.28, 1.27,1.26, 1.25
Nginx Version 1.21.6
wget -k https://github.com/kubernetes/ingress-nginx/raw/main/deploy/static/provider/kind/deploy.yaml -O ingress-nginx.yaml

cat ingress-nginx.yaml

apiVersion: v1
kind: Namespace
metadata:
  labels:
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
  name: ingress-nginx
---
apiVersion: v1
automountServiceAccountToken: true
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx
  namespace: ingress-nginx
---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/component: admission-webhook
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx-admission
  namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx
  namespace: ingress-nginx
rules:
- apiGroups:
  - ""
  resources:
  - namespaces
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - configmaps
  - pods
  - secrets
  - endpoints
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - services
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - networking.k8s.io
  resources:
  - ingresses
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - networking.k8s.io
  resources:
  - ingresses/status
  verbs:
  - update
- apiGroups:
  - networking.k8s.io
  resources:
  - ingressclasses
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - coordination.k8s.io
  resourceNames:
  - ingress-nginx-leader
  resources:
  - leases
  verbs:
  - get
  - update
- apiGroups:
  - coordination.k8s.io
  resources:
  - leases
  verbs:
  - create
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - patch
- apiGroups:
  - discovery.k8s.io
  resources:
  - endpointslices
  verbs:
  - list
  - watch
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  labels:
    app.kubernetes.io/component: admission-webhook
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx-admission
  namespace: ingress-nginx
rules:
- apiGroups:
  - ""
  resources:
  - secrets
  verbs:
  - get
  - create
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx
rules:
- apiGroups:
  - ""
  resources:
  - configmaps
  - endpoints
  - nodes
  - pods
  - secrets
  - namespaces
  verbs:
  - list
  - watch
- apiGroups:
  - coordination.k8s.io
  resources:
  - leases
  verbs:
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - services
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - networking.k8s.io
  resources:
  - ingresses
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - patch
- apiGroups:
  - networking.k8s.io
  resources:
  - ingresses/status
  verbs:
  - update
- apiGroups:
  - networking.k8s.io
  resources:
  - ingressclasses
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - discovery.k8s.io
  resources:
  - endpointslices
  verbs:
  - list
  - watch
  - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    app.kubernetes.io/component: admission-webhook
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx-admission
rules:
- apiGroups:
  - admissionregistration.k8s.io
  resources:
  - validatingwebhookconfigurations
  verbs:
  - get
  - update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx
  namespace: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: ingress-nginx
subjects:
- kind: ServiceAccount
  name: ingress-nginx
  namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  labels:
    app.kubernetes.io/component: admission-webhook
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx-admission
  namespace: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
  name: ingress-nginx-admission
  namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: ingress-nginx
subjects:
- kind: ServiceAccount
  name: ingress-nginx
  namespace: ingress-nginx
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  labels:
    app.kubernetes.io/component: admission-webhook
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx-admission
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: ingress-nginx-admission
subjects:
- kind: ServiceAccount
  name: ingress-nginx-admission
  namespace: ingress-nginx
---
apiVersion: v1
data:
  allow-snippet-annotations: "false"
kind: ConfigMap
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx-controller
  namespace: ingress-nginx
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - appProtocol: http
    name: http
    port: 80
    protocol: TCP
    targetPort: http
    #nodePort: 30080
  - appProtocol: https
    name: https
    port: 443
    protocol: TCP
    targetPort: https
    #nodePort: 30443
  selector:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
  type: NodePort
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx-controller-admission
  namespace: ingress-nginx
spec:
  ports:
  - appProtocol: https
    name: https-webhook
    port: 443
    targetPort: webhook
  selector:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
  type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  replicas: 1
  minReadySeconds: 0
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app.kubernetes.io/component: controller
      app.kubernetes.io/instance: ingress-nginx
      app.kubernetes.io/name: ingress-nginx
  strategy:
    rollingUpdate:
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      labels:
        app.kubernetes.io/component: controller
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.9.3
    spec:
      dnsPolicy: ClusterFirstWithHostNet  #既能使用宿主机DNS,又能使用集群DNS
      hostNetwork: true                   #与宿主机共享网络
      #nodeName: node01.k8s.local              #设置只能在k8snode1节点运行
      tolerations:                        #设置能容忍master污点
      - key: node-role.kubernetes.io/master
        operator: Exists
      containers:
      - args:
        - /nginx-ingress-controller
        - --election-id=ingress-nginx-leader
        - --controller-class=k8s.io/ingress-nginx
        - --ingress-class=nginx
        - --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
        - --validating-webhook=:8443
        - --validating-webhook-certificate=/usr/local/certificates/cert
        - --validating-webhook-key=/usr/local/certificates/key
        - --watch-ingress-without-class=true
        - --publish-status-address=localhost
        - --logtostderr=false
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: LD_PRELOAD
          value: /usr/local/lib/libmimalloc.so
        image:  repo.k8s.local/registry.k8s.io/ingress-nginx/controller:v1.9.3
        imagePullPolicy: IfNotPresent
        lifecycle:
          preStop:
            exec:
              command:
              - /wait-shutdown
        livenessProbe:
          failureThreshold: 5
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        name: controller
        ports:
        - containerPort: 80
          hostPort: 80
          name: http
          protocol: TCP
        - containerPort: 443
          hostPort: 443
          name: https
          protocol: TCP
        - containerPort: 8443
          name: webhook
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        resources:
          requests:
            cpu: 100m
            memory: 90Mi
        securityContext:
          allowPrivilegeEscalation: true
          capabilities:
            add:
            - NET_BIND_SERVICE
            drop:
            - ALL
          runAsUser: 101
        volumeMounts:
        - mountPath: /usr/local/certificates/
          name: webhook-cert
          readOnly: true
        - name: timezone
          mountPath: /etc/localtime  
        - name: vol-ingress-logdir
          mountPath: /var/log/nginx
      #dnsPolicy: ClusterFirst
      nodeSelector:
        ingresstype: ingress-nginx
        kubernetes.io/os: linux
      serviceAccountName: ingress-nginx
      terminationGracePeriodSeconds: 0
      tolerations:
      - effect: NoSchedule
        key: node-role.kubernetes.io/master
        operator: Equal
      - effect: NoSchedule
        key: node-role.kubernetes.io/control-plane
        operator: Equal
      volumes:
      - name: timezone       
        hostPath:
          path: /usr/share/zoneinfo/Asia/Shanghai  
      - name: vol-ingress-logdir
        hostPath:
          path: /var/log/nginx
          type: DirectoryOrCreate
      - name: webhook-cert
        secret:
          secretName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
  labels:
    app.kubernetes.io/component: admission-webhook
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx-admission-create
  namespace: ingress-nginx
spec:
  template:
    metadata:
      labels:
        app.kubernetes.io/component: admission-webhook
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.9.3
      name: ingress-nginx-admission-create
    spec:
      containers:
      - args:
        - create
        - --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
        - --namespace=$(POD_NAMESPACE)
        - --secret-name=ingress-nginx-admission
        env:
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        image:  repo.k8s.local/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20231011-8b53cabe0
        imagePullPolicy: IfNotPresent
        name: create
        securityContext:
          allowPrivilegeEscalation: false
      nodeSelector:
        kubernetes.io/os: linux
      restartPolicy: OnFailure
      securityContext:
        fsGroup: 2000
        runAsNonRoot: true
        runAsUser: 2000
      serviceAccountName: ingress-nginx-admission
---
apiVersion: batch/v1
kind: Job
metadata:
  labels:
    app.kubernetes.io/component: admission-webhook
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx-admission-patch
  namespace: ingress-nginx
spec:
  template:
    metadata:
      labels:
        app.kubernetes.io/component: admission-webhook
        app.kubernetes.io/instance: ingress-nginx
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
        app.kubernetes.io/version: 1.9.3
      name: ingress-nginx-admission-patch
    spec:
      containers:
      - args:
        - patch
        - --webhook-name=ingress-nginx-admission
        - --namespace=$(POD_NAMESPACE)
        - --patch-mutating=false
        - --secret-name=ingress-nginx-admission
        - --patch-failure-policy=Fail
        env:
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        image:  repo.k8s.local/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20231011-8b53cabe0
        imagePullPolicy: IfNotPresent
        name: patch
        securityContext:
          allowPrivilegeEscalation: false
      nodeSelector:
        kubernetes.io/os: linux
      restartPolicy: OnFailure
      securityContext:
        fsGroup: 2000
        runAsNonRoot: true
        runAsUser: 2000
      serviceAccountName: ingress-nginx-admission
---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: nginx
spec:
  controller: k8s.io/ingress-nginx
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  labels:
    app.kubernetes.io/component: admission-webhook
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx-admission
  namespace: ingress-nginx
spec:
  egress:
  - {}
  podSelector:
    matchLabels:
      app.kubernetes.io/component: admission-webhook
      app.kubernetes.io/instance: ingress-nginx
      app.kubernetes.io/name: ingress-nginx
  policyTypes:
  - Ingress
  - Egress
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  labels:
    app.kubernetes.io/component: admission-webhook
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx-admission
webhooks:
- admissionReviewVersions:
  - v1
  clientConfig:
    service:
      name: ingress-nginx-controller-admission
      namespace: ingress-nginx
      path: /networking/v1/ingresses
  failurePolicy: Fail
  matchPolicy: Equivalent
  name: validate.nginx.ingress.kubernetes.io
  rules:
  - apiGroups:
    - networking.k8s.io
    apiVersions:
    - v1
    operations:
    - CREATE
    - UPDATE
    resources:
    - ingresses
  sideEffects: None
提取image名称,并在harbor 导入
cat ingress-nginx.yaml |grep image:|sed -e 's/.*image: //'

registry.k8s.io/ingress-nginx/controller:v1.9.3@sha256:8fd21d59428507671ce0fb47f818b1d859c92d2ad07bb7c947268d433030ba98
registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20231011-8b53cabe0@sha256:a7943503b45d552785aa3b5e457f169a5661fb94d82b8a3373bcd9ebaf9aac80
registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20231011-8b53cabe0@sha256:a7943503b45d552785aa3b5e457f169a5661fb94d82b8a3373bcd9ebaf9aac80
#切换到harbor
docker pull registry.aliyuncs.com/google_containers/nginx-ingress-controller:v1.9.3
docker pull registry.aliyuncs.com/google_containers/kube-webhook-certgen:v20231011-8b53cabe0

docker tag registry.aliyuncs.com/google_containers/nginx-ingress-controller:v1.9.3  repo.k8s.local/registry.k8s.io/ingress-nginx/controller:v1.9.3
docker tag registry.aliyuncs.com/google_containers/kube-webhook-certgen:v20231011-8b53cabe0  repo.k8s.local/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20231011-8b53cabe0
docker push repo.k8s.local/registry.k8s.io/ingress-nginx/controller:v1.9.3
docker push repo.k8s.local/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20231011-8b53cabe0

docker images |grep ingress

修改yaml为私仓地址
方式一
修改image: 为私仓地址

sed -n "/image:/{s/image: /image: repo.k8s.local\//p}" ingress-nginx.yaml
sed -i "/image:/{s/image: /image: repo.k8s.local\//}" ingress-nginx.yaml
去除@sha256验证码
sed -rn "s/(\s*image:.*)@sha256:.*$/\1 /gp" ingress-nginx.yaml
sed -ri "s/(\s*image:.*)@sha256:.*$/\1 /g" ingress-nginx.yaml

方式二

合并执行,替换为私仓并删除SHA256验证

sed -rn "s/(\s*image: )(.*)@sha256:.*$/\1 repo.k8s.local\/\2/gp" ingress-nginx.yaml
sed -ri "s/(\s*image: )(.*)@sha256:.*$/\1 repo.k8s.local\/\2/g" ingress-nginx.yaml

方式三
手动编辑文件
vi ingress-nginx.yaml

cat ingress-nginx.yaml |grep image:
        image:  repo.k8s.local/registry.k8s.io/ingress-nginx/controller:v1.9.3
        image:  repo.k8s.local/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20231011-8b53cabe0
        image:  repo.k8s.local/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v20231011-8b53cabe0

Deployment nodeName 方式

通常调式用,分配到指定的node,无法自动调度

vi ingress-nginx.yaml

kind: Deployment

      dnsPolicy: ClusterFirstWithHostNet  #既能使用宿主机DNS,又能使用集群DNS
      hostNetwork: true                   #与宿主机共享网络,接在主机上开辟 80,443端口,无需中间解析,速度更快
      nodeName: node01.k8s.local              #设置只能在k8snode1节点运行

Deployment+nodeSelector 方式

可以调度到带有指定标签的node,可以给node打标签来调度,这里布署ingress更推荐daemonset

vi ingress-nginx.yaml

kind: Deployment
spec:
  replicas: 1 #副本数,默认一个node一个
      dnsPolicy: ClusterFirstWithHostNet  #既能使用宿主机DNS,又能使用集群DNS
      hostNetwork: true                   #与宿主机共享网络,接在主机上开辟 80,443端口,无需中间解析,速度更快
      #nodeName: node01.k8s.local              #设置只能在k8snode1节点运行
      tolerations:                        #设置能容忍master污点
      - key: node-role.kubernetes.io/master
        operator: Exists

      nodeSelector:
        ingresstype: ingress-nginx
        kubernetes.io/os: linux

kind: Service
  ports:
     - name: http
       nodePort: 30080   #固定端口
     - name: https
       nodePort: 30443   #固定端口

DaemonSet 方式

每个node带有标签的node都分配一个

在Deployment:spec指定布署节点
修改Deployment为DaemonSet
修改时同步注释掉

  #replicas: 1
  #strategy:
  #  rollingUpdate:
  #    maxUnavailable: 1
  #  type: RollingUpdate

修改DaemonSet的nodeSelector: ingress-node=true 。这样只需要给node节点打上 ingresstype=ingress-nginx 标签,即可快速的加入/剔除 ingress-controller的数量

vi ingress-nginx.yaml

kind: DaemonSet

      dnsPolicy: ClusterFirstWithHostNet  #既能使用宿主机DNS,又能使用集群DNS
      hostNetwork: true                   #与宿主机共享网络,接在主机上开辟 80,443端口,无需中间解析,速度更快,netstat 可以看到端口
      #nodeName: node01.k8s.local              #设置只能在k8snode1节点运行
      tolerations:                        #设置能容忍master污点,充许布到master
      - key: node-role.kubernetes.io/master
        operator: Exists
      nodeSelector:
        ingresstype: ingress-nginx
        kubernetes.io/os: linux

NodeSelector 只是一种简单的调度策略,更高级的调度策略可以使用 Node Affinity 和 Node Taints 等机制来实现

kubectl apply -f ingress-nginx.yaml

kubectl delete -f ingress-nginx.yaml

kubectl get pods -A
NAMESPACE              NAME                                                    READY   STATUS      RESTARTS        AGE
default                nfs-client-provisioner-db4f6fb8-gnnbm                   1/1     Running     0               24h
ingress-nginx          ingress-nginx-admission-create-wxtlz                    0/1     Completed   0               103s
ingress-nginx          ingress-nginx-admission-patch-8fw72                     0/1     Completed   1               103s
ingress-nginx          ingress-nginx-controller-57c98745dd-2rn7m               0/1     Pending     0               103s

查看详情

kubectl -n ingress-nginx describe pod ingress-nginx-controller-57c98745dd-2rn7m

didn’t match Pod’s node affinity/selector. preemption: 0/3 nodes are available: 3 Preemption is not helpful for scheduling..
无法调度到正确Node
影响调度的因素:nodename、NodeSelector、Node Affinity、Pod Affinity、taint和tolerations
这里还没有给node打标签ingresstype=ingress-nginx,所以不能调度

如果布署成功可以看到分配到哪台node

Service Account: ingress-nginx
Node: node01.k8s.local/192.168.244.5

查看nodes

kubectl get nodes

NAME                 STATUS   ROLES           AGE     VERSION
master01.k8s.local   Ready    control-plane   9d      v1.28.2
node01.k8s.local     Ready    <none>          9d      v1.28.2
node02.k8s.local     Ready    <none>          2d23h   v1.28.2

查看node是否被打污点

kubectl describe nodes | grep Tain

Taints:             node-role.kubernetes.io/control-plane:NoSchedule
Taints:             <none>
Taints:             <none>

查看node的标签

kubectl get node –show-labels

NAME                 STATUS   ROLES           AGE     VERSION   LABELS
master01.k8s.local   Ready    control-plane   12d     v1.28.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master01.k8s.local,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
node01.k8s.local     Ready    <none>          12d     v1.28.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node01.k8s.local,kubernetes.io/os=linux
node02.k8s.local     Ready    <none>          6d16h   v1.28.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node02.k8s.local,kubernetes.io/os=linux
kubectl get node -l "ingresstype=ingress-nginx" -n ingress-nginx --show-labels
kubectl get node -l "beta.kubernetes.io/arch=amd64" -n ingress-nginx --show-labels

查看是否是node资源不足

在 Linux 中查看实际剩余的 cpu

kubectl describe node |grep -E '((Name|Roles):\s{6,})|(\s+(memory|cpu)\s+[0-9]+\w{0,2}.+%\))'

给需要的node节点上部署ingress-controller:

因为我们使用的是DaemonSet模式,所以理论上会为所有的节点都安装,但是由于我们的selector使用了筛选标签:ingresstype=ingress-nginx ,所以此时所有的node节点都没有被执行安装;
kubectl get ds -n ingress-nginx

NAME                       DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                                     AGE
ingress-nginx-controller   0         0         0       0            0           ingresstype=ingress-nginx,kubernetes.io/os=linux   60s

查询详细

kubectl describe ds -n ingress-nginx

当我们需要为所有的node节点安装ingress-controller的时候,只需要为对应的节点打上标签:node-role=ingress-ready

kubectl label node node01.k8s.local ingresstype=ingress-nginx
kubectl label node node02.k8s.local ingresstype=ingress-nginx
kubectl label node master01.k8s.local ingresstype=ingress-nginx

修改标签,需要增加–overwrite这个参数(为了与增加标签的命令做区分)

kubectl label node node01.k8s.local ingresstype=ingress-nginx --overwrite

删除node的标签

kubectl label node node01.k8s.local node-role-
kubectl label node node01.k8s.local ingress-

kubectl get node –show-labels

NAME                 STATUS   ROLES           AGE     VERSION   LABELS
NAME                 STATUS   ROLES           AGE     VERSION   LABELS
master01.k8s.local   Ready    control-plane   13d     v1.28.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,ingresstype=ingress-nginx,kubernetes.io/arch=amd64,kubernetes.io/hostname=master01.k8s.local,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node.kubernetes.io/exclude-from-external-load-balancers=
node01.k8s.local     Ready              13d     v1.28.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,ingresstype=ingress-nginx,kubernetes.io/arch=amd64,kubernetes.io/hostname=node01.k8s.local,kubernetes.io/os=linux
node02.k8s.local     Ready              6d19h   v1.28.2   beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,ingresstype=ingress-nginx,kubernetes.io/arch=amd64,kubernetes.io/hostname=node02.k8s.local,kubernetes.io/os=linux

查看当前有3个节点

kubectl get ds -n ingress-nginx

NAME                       DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR               AGE
ingress-nginx-controller   3         3         3       3            3           ingresstype=ingress-nginx,kubernetes.io/os=linux   25s

删除标签后,主节点就被移除了,只有2个节点
kubectl label node master01.k8s.local ingresstype-

kubectl get pods -A

NAMESPACE              NAME                                                    READY   STATUS      RESTARTS       AGE
default                nfs-client-provisioner-db4f6fb8-gnnbm                   1/1     Running     10 (26h ago)   4d20h
ingress-nginx          ingress-nginx-admission-create-zxz7j                    0/1     Completed   0              3m35s
ingress-nginx          ingress-nginx-admission-patch-xswhk                     0/1     Completed   1              3m35s
ingress-nginx          ingress-nginx-controller-7j4nz                          1/1     Running     0              3m35s
ingress-nginx          ingress-nginx-controller-g285w                          1/1     Running     0              3m35s

kubectl get svc -n ingress-nginx

NAME                                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             NodePort    10.96.116.106           80:30080/TCP,443:30443/TCP   8m26s
ingress-nginx-controller-admission   ClusterIP   10.96.104.116           443/TCP                      8m26s

kubectl -n ingress-nginx describe pod ingress-nginx-controller-7f6c656666-gn4f2

Warning  FailedMount  112s  kubelet                   MountVolume.SetUp failed for volume "webhook-cert" : secret "ingress-nginx-admission" not found

从Deployment改成DaemonSet,如果有足够资源可以直接改yaml后apply,分配后资源不足会的pod会一直Pending,老的pod依然running,提示以下资源不足信息.
Warning FailedScheduling 33s default-scheduler 0/3 nodes are available: 1 node(s) didn't have free ports for the requested pod ports. preemption: 0/3 nodes are available: 3 No preemption victims found for incoming pod..
手动删除老pod后,新pod可以自动运行,但老的pod一直重新生成新的pending pod
kubectl -n ingress-nginx delete pod ingress-nginx-controller-6c95999b7f-njzvr

创建一个nginx测试

准备镜像
docker pull docker.io/library/nginx:1.21.4
docker tag docker.io/library/nginx:1.21.4 repo.k8s.local/library/nginx:1.21.4
docker push repo.k8s.local/library/nginx:1.21.4
nginx yaml文件
#使用Deployment+nodeName+hostPath,指定分配到node01上
cat > test-nginx-hostpath.yaml < svc-test-nginx-nodeport.yaml < svc-test-nginx-clusterip.yaml <

Ingress规则,将ingress和service绑一起
podip和clusterip都不固定,但是service name是固定的
namespace 要一致

注意1.22版前,yaml格式有差异

apiVersion: extensions/v1beta1
    backend:
      serviceName: svc-test-nginx
      servicePort: 80
cat > ingress-svc-test-nginx.yaml  << EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-svc-test-nginx
  annotations:
    #kubernetes.io/ingress.class: "nginx"
  namespace: test
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /testpath
        pathType: Prefix
        backend:
          service:
            name: svc-test-nginx
            port:
              number: 31080
EOF
在node1 上创建本地文件夹,后续pod因spec:nodeName: 会分配到此机。  
mkdir -p /nginx/{html,logs,conf.d}

#生成一个首页
echo hostname > /nginx/html/index.html
echo date >> /nginx/html/index.html

#生成ingress测试页
mkdir  /nginx/html/testpath/
echo hostname > /nginx/html/testpath/index.html

kubectl apply -f test-nginx-hostpath.yaml
kubectl delete -f test-nginx-hostpath.yaml

#service nodeport/clusterip 两者选一
kubectl apply -f svc-test-nginx-nodeport.yaml
kubectl delete -f svc-test-nginx-nodeport.yaml

#service clusterip
kubectl apply -f svc-test-nginx-clusterip.yaml
kubectl delete -f svc-test-nginx-clusterip.yaml

kubectl apply -f ingress-svc-test-nginx.yaml
kubectl delete -f ingress-svc-test-nginx.yaml
kubectl describe ingress ingress-svc-test-hostpath -n test

kubectl get pods -n test
kubectl describe  -n test pod nginx-deploy-5bc84b775f-hnqll 
kubectl get svc -A

注删pod重启后文件会被重写,html/和logs 不会覆盖

ll /nginx/conf.d/ 

total 4
-rw-r--r-- 1 root root 1072 Oct 26 11:06 default.conf

cat /nginx/conf.d/default.conf
server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}
EOF

使用nodeport
kubectl get service -n test

NAME             TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)           AGE
svc-test-nginx   NodePort   10.96.148.126           31080:30003/TCP   20s

使用clusterip
kubectl get service -n test

NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)     AGE
svc-test-nginx   ClusterIP   10.96.209.131           31080/TCP   80s

总结一下如何访问到pod内web服务

ip规则
node节点:192.168.244.0/24
pod网段:10.244.0.0/16
service网段(集群网段):10.96.0.0/12

ingress为HostNetwork模式

集群内外可以访问到ingress匹配到的node上的nodeip+80和443
curl http://192.168.244.5:80/

 集群内外通过service nodeport访问任意nodeip+nodePort

ingress service 的nodeip+nodeport
此例中30080为ingress的nodeport
curl http://192.168.244.4:30080/testpath/
node01.k8s.local

nginx service 的nodeip+nodeport
service为 nodeport 在集群内或外部使用任意nodeip+nodeport,访问pod上的nginx
curl http://192.168.244.5:30003
node01.k8s.local
Thu Oct 26 11:11:00 CST 2023

 集群内通过service clusterip

ingress service 的clusterip+clusterport
curl http://10.96.111.201:80/testpath/
node01.k8s.local

nginx service 的clusterip+clusterport
在集群内使用clusterip+cluster port,也就是service 访问内部nginx,只有集群内能访问,每次重启pod clusterip会变动,测试使用
curl http://10.96.148.126:31080
node01.k8s.local
Thu Oct 26 11:11:00 CST 2023

集群内通过pod ip

nginx podip+port
curl http://10.244.1.93:80

pod内可以用service域名来访问

curl http://svc-test-nginx:31080
curl http://svc-test-nginx.test:31080
curl http://svc-test-nginx.test.svc.cluster.local:31080
curl http://10.96.148.126:31080


在node1上可以看到访问日志,注意日期的时区是不对的

tail -f /nginx/logs/access.log

10.244.0.0 - - [26/Oct/2023:03:11:04 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.289 Safari/537.36" "-"

pod中时区问题
时区可以在yaml中用hostpath指到宿主机的时区文件

        volumeMounts:
        - name: timezone
          mountPath: /etc/localtime  
      volumes:
      - name: timezone       
        hostPath:
          path: /usr/share/zoneinfo/Asia/Shanghai  

kubectl get pods -o wide -n test

进入容器

kubectl exec -it pod/nginx-deploy-886d78bd5-wlk5l -n test -- /bin/sh

Ingress-nginx 组件添加和设置 header

Ingress-nginx 可以通过 snippets注解 的方式配置,但为了安全起见,默认情况下,snippets注解 不允许的
https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#allow-snippet-annotations
这种方式只能给具体的 ingress 资源配置,如果需要给所有ingress 接口配置就很麻烦, 维护起来很不优雅.所以推荐通过官方提供的 自定义Header 的方式来配置

https://help.aliyun.com/zh/ack/ack-managed-and-ack-dedicated/user-guide/ install-the-nginx-ingress-controller-in-high-load-scenarios
ingress默认会丢弃不标准的http头
https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/#proxy-real-ip-cidr
解决:configmaps添加

data:
 enable-underscores-in-headers: "true"
cat > ingress-nginx-ConfigMap.yaml <
#注意文本中含用变量,使用vi 编辑模式修改.
#realip 生效在http段,snippet生效在server段
vi ingress-nginx-ConfigMap.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
    app.kubernetes.io/version: 1.9.3
  name: ingress-nginx-controller
  namespace: ingress-nginx
data:
  allow-snippet-annotations: "true"
  worker-processes: "auto" #worker_processes
  server-name-hash-bucket-size: "128" #server_names_hash_bucket_size
  variables-hash-bucket-size: "256" #variables_hash_bucket_size
  variables-hash-max-size: "2048" #variables_hash_max_size
  client-header-buffer-size: "32k" #client_header_buffer_size
  proxy-body-size: "8m" #client_max_body_size
  large-client-header-buffers: "4 512k" #large_client_header_buffers
  client-body-buffer-size: "512k" #client_body_buffer_size
  proxy-connect-timeout : "5" #proxy_connect_timeout
  proxy-read-timeout: "60" #proxy_read_timeout
  proxy-send-timeout: "5" #proxy_send_timeout
  proxy-buffer-size: "32k" #proxy_buffer_size
  proxy-buffers-number: "8 32k" #proxy_buffers
  keep-alive: "60" #keepalive_timeout
  enable-real-ip: "true" 
  #use-forwarded-headers: "true"
  forwarded-for-header: "ns_clientip" #real_ip_header
  compute-full-forwarded-for: "true"
  enable-underscores-in-headers: "true" #underscores_in_headers on
  proxy-real-ip-cidr: 192.168.0.0/16,10.244.0.0/16  #set_real_ip_from
  access-log-path: "/var/log/nginx/access_ext_ingress_$hostname.log"
  error-log-path: "/var/log/nginx/error_ext_ingress.log"
  log-format-escape-json: "true"
  log-format-upstream: '{"timestamp": "$time_iso8601", "req_id": "$req_id", 
    "geoip_country_code": "$geoip_country_code", "request_time": "$request_time", 
    "ingress":{ "hostname": "$hostname", "addr": "$server_addr", "port": "$server_port","namespace": "$namespace","ingress_name": "$ingress_name","service_name": "$service_name","service_port": "$service_port" }, 
    "upstream":{ "addr": "$upstream_addr", "name": "$proxy_upstream_name", "response_time": "$upstream_response_time", 
    "status": "$upstream_status", "response_length": "$upstream_response_length", "proxy_alternative": "$proxy_alternative_upstream_name"}, 
    "request":{ "remote_addr": "$remote_addr", "real_ip": "$realip_remote_addr", "remote_port": "$remote_port", "real_port": "$realip_remote_port", 
    "remote_user": "$remote_user", "request_method": "$request_method", "hostname": "$host", "request_uri": "$request_uri", "status": $status, 
    "body_bytes_sent": "$body_bytes_sent", "request_length": "$request_length", "referer": "$http_referer", "user_agent": "$http_user_agent",
    "x-forward-for": "$proxy_add_x_forwarded_for", "protocol": "$server_protocol"}}'

创建/关闭 ConfigMap

kubectl apply -f ingress-nginx-ConfigMap.yaml -n ingress-nginx
直接生效,不需重启pod
kubectl delete -f ingress-nginx-ConfigMap.yaml

kubectl get pods -o wide -n ingress-nginx

ingress-nginx-controller-kr8jd         1/1     Running     6 (7m26s ago)   13m     192.168.244.7   node02.k8s.local   

查看ingress-nginx 配制文件

kubectl describe pod/ingress-nginx-controller-z5b4f -n ingress-nginx 
kubectl exec -it pod/ingress-nginx-controller-z5b4f -n ingress-nginx -- /bin/sh
kubectl exec -it pod/ingress-nginx-controller-kr8jd -n ingress-nginx -- head -n200 /etc/nginx/nginx.conf
kubectl exec -it pod/ingress-nginx-controller-kr8jd -n ingress-nginx -- cat /etc/nginx/nginx.conf
kubectl exec -it pod/ingress-nginx-controller-z5b4f -n ingress-nginx -- tail /var/log/nginx/access.log

kubectl exec -it pod/ingress-nginx-controller-kr8jd -n ingress-nginx -- head -n200 /etc/nginx/nginx.conf|grep client_body_buffer_size

客户端->CDN->WAF->SLB->Ingress->Pod

realip

方式一 kind: ConfigMap

  enable-real-ip: "true" 
  #use-forwarded-headers: "true"
  forwarded-for-header: "ns_clientip" #real_ip_header
  compute-full-forwarded-for: "true"
  enable-underscores-in-headers: "true" #underscores_in_headers on
  proxy-real-ip-cidr: 192.168.0.0/16,10.244.0.0/16  #set_real_ip_from

方式二 server-snippet
kind: ConfigMap中打开
allow-snippet-annotations: "true"

kubectl edit configmap -n ingress-nginx ingress-nginx-controller

#ingress关联server-snippet
#realip 会在server 段对全域名生效
#ip 白名单whitelist-source-range 会在location = /showvar 生效,使用remoteaddr判定,需要全域白名单时才用.allow 223.2.2.0/24;deny all;

test-openresty-ingress-snippet.yaml
用cat时在含有变量时需转义\$ ,vi 不用转义
cat > test-openresty-ingress-snippet.yaml  << EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-svc-openresty
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/server-snippet: |
      underscores_in_headers on;
      set_real_ip_from 10.244.0.0/16;
      set_real_ip_from 192.168.0.0/16;
      real_ip_header ns_clientip;
      #real_ip_recursive on;
      proxy_set_header                X-Forwarded-For \$proxy_add_x_forwarded_for;
      add_header      Access-Control-Allow-Headers    \$http_Access_Control_Request_Headers    always;
      add_header      Access-Control-Allow-Origin     \$http_Origin    always;
      add_header      Access-Control-Allow-Credentials        'false' always;
      add_header      Access-Control-Allow-Methods    '*'     always;
      if (\$request_method = 'OPTIONS') {
            return 204;
      }
    nginx.ingress.kubernetes.io/whitelist-source-range: 127.0.0.1/32,192.168.0.0/16,10.244.0.0/16,223.2.2.0/24
  namespace: test
spec:
  rules:
  - http:
      paths:
      - path: /showvar
        pathType: Prefix
        backend:
          service:
            name: svc-openresty
            port:
              number: 31080
EOF

kubectl apply -f test-openresty-ingress-snippet.yaml
  1. enable-real-ip:
    enable-real-ip: "true"
    打开real-ip
    生成的代码

        real_ip_header      X-Forwarded-For;
        real_ip_recursive   on;
        set_real_ip_from    0.0.0.0/0;
  2. use-forwarded-headers:
    use-forwarded-headers: "false" 适用于 Ingress 前无代理层,例如直接挂在 4 层 SLB 上,ingress 默认重写 X-Forwarded-For 为 $remote_addr ,可防止伪造 X-Forwarded-For
    use-forwarded-headers: "true" 适用于 Ingress 前有代理层,风险是可以伪造X-Forwarded-For
    生成的代码

        real_ip_header      X-Forwarded-For;
        real_ip_recursive   on;
        set_real_ip_from    0.0.0.0/0;
  3. enable-underscores-in-headers​​​:
    enable-underscores-in-headers: "true"
    是否在hader头中启用非标的_下划线, 缺省默认为"false",如充许 X_FORWARDED_FOR 头,请设为"true"。​​
    相当于nginx的 underscores_in_headers on;

  4. forwarded-for-header
    默认值 X-Forwarded-For,标识客户端的原始 IP 地址的 Header 字段, 如自定义的header头 X_FORWARDED_FOR
    forwarded-for-header: "X_FORWARDED_FOR"
    相当于nginx的real_ip_header

4.compute-full-forwarded-for
默认会将remote替换X-Forwarded-For​
将 remote address 附加到 X-Forwarded-For Header而不是替换它。

  1. ​​proxy-real-ip-cidr​
    如果启用 ​​use-forwarded-headers​​ 或 ​​use-proxy-protocol​​,则可以使用该参数其定义了外部负载衡器 、网络代理、CDN等地址,多个地址可以以逗号分隔的 CIDR 。默认值: "0.0.0.0/0"
    set_real_ip_from

6.external-traffic-policy
Cluster模式:是默认模式,Kube-proxy不管容器实例在哪,公平转发,会做一次SNAT,所以源IP变成了节点1的IP地址。
Local模式:流量只发给本机的Pod,Kube-proxy转发时会保留源IP,性能(时延)好。
这种模式下的Service类型只能为外部流量,即:LoadBalancer 或者 NodePort 两种,否则会报错

开realip后 http_x_forwarded_for 值被会被 remoteaddr 取代
如果compute-full-forwarded-for: "true" ,那么remoteaddr会被追加到右侧
由于本机不会跨节点转发报文,所以要想所有节点上的容器有负载均衡,就需要依赖上一级的Loadbalancer来实现

日 志

access-log-path: /var/log/nginx/access.log
/var/log/nginx/access.log -> /dev/stdout

error-log-path:/var/log/nginx/error.log
/var/log/nginx/error.log->/dev/stderr

kubectl get ds -A
kubectl get ds -n ingress-nginx ingress-nginx-controller -o=yaml
将当前damonset布署的ingress-nginx-controller 导出成单独yaml,方便修改
kubectl get ds -n ingress-nginx ingress-nginx-controller -o=yaml > ingress-nginx-deployment.yaml

每个node上
自动创建的目录为root:root ,而ingress没权限写入
mkdir -p /var/log/nginx/
chmod 777 /var/log/nginx/

Error: exit status 1
nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (13: Permission denied)
nginx: the configuration file /tmp/nginx/nginx-cfg1271722019 syntax is ok
2023/11/02 14:05:02 [emerg] 34#34: open() "/var/log/nginx/access.log" failed (13: Permission denied)
nginx: configuration file /tmp/nginx/nginx-cfg1271722019 test failed

kind: Deployment 中 关闭 logtostderr

  • --logtostderr=false
    示例:

    
      containers:
      - args:
  • /nginx-ingress-controller
  • --election-id=ingress-nginx-leader
  • --controller-class=k8s.io/ingress-nginx
  • --ingress-class=nginx
  • --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
  • --validating-webhook=:8443
  • --validating-webhook-certificate=/usr/local/certificates/cert
  • --validating-webhook-key=/usr/local/certificates/key
  • --watch-ingress-without-class=true
  • --publish-status-address=localhost
  • --logtostderr=false

挂载到宿主目录

        volumeMounts:
        - name: timezone
          mountPath: /etc/localtime  
        - name: vol-ingress-logdir
          mountPath: /var/log/nginx
      volumes:
      - name: timezone       
        hostPath:
          path: /usr/share/zoneinfo/Asia/Shanghai  
      - name: vol-ingress-logdir
        hostPath:
          path: /var/log/nginx
          type: DirectoryOrCreate

创建/关闭 ingress-nginx-deployment

kubectl apply -f ingress-nginx-deployment.yaml

kubectl get pods -o wide -n ingress-nginx

默认日志格式

        log_format upstreaminfo '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length $request_time [$proxy_upstream_name] [$proxy_alternative_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status $req_id';

tail -f /var/log/nginx/access.log
3.2.1.5 - - [02/Nov/2023:14:11:26 +0800] "GET /showvar/?2 HTTP/1.1" 200 316 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.289 Safari/537.36" 764 0.000 [test-svc-openresty-31080] [] 10.244.2.46:8089 316 0.000 200 a9051a75e20e164f1838740e12fa95e3

SpringCloud 微服务 RuoYi-Cloud 部署文档(DevOps版)(2023-10-18) argo-rollouts + istio(金丝雀发布)(渐进式交付)
https://blog.csdn.net/weixin_44797299/article/details/133923956

server-snippet 访问验证 和URL重定向(permanent):

通过Ingress注解nginx.ingress.kubernetes.io/server-snippet配置location,访问/sre,返回401错误代码

cat > test-openresty-ingress-snippet.yaml  << EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-svc-openresty
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/server-snippet: |
      underscores_in_headers on;
      set_real_ip_from 10.244.0.0/16;
      set_real_ip_from 192.168.0.0/16;
      real_ip_header ns_clientip;
      #real_ip_recursive on;      
      location /sre {
        return 401;
      }
      rewrite ^/baidu.com$ https://www.baidu.com redirect;
    nginx.ingress.kubernetes.io/whitelist-source-range: 127.0.0.1/32,192.168.0.0/16,10.244.0.0/16,223.2.2.0/24
  namespace: test
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /showvar
        pathType: Prefix
        backend:
          service:
            name: svc-openresty
            port:
              number: 31080
EOF

kubectl apply -f test-openresty-ingress-snippet.yaml

curl http://192.168.244.7:80/sre/ 

401 Authorization Required

401 Authorization Required


nginx
curl http://192.168.244.7:80/baidu.com 302 Found

302 Found


nginx

configuration-snippet

nginx.ingress.kubernetes.io/denylist-source-range
扩展配置到Location章节
cat > test-openresty-ingress-snippet.yaml << EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-svc-openresty
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/server-snippet: |
underscores_in_headers on;
set_real_ip_from 10.244.0.0/16;
set_real_ip_from 192.168.0.0/16;
real_ip_header ns_clientip;

real_ip_recursive on;

  location /sre {
    return 401;
  }
  rewrite ^/baidu.com$ https://www.baidu.com redirect;
nginx.ingress.kubernetes.io/whitelist-source-range: 127.0.0.1/32,192.168.0.0/16,10.244.0.0/16,223.2.2.0/24
nginx.ingress.kubernetes.io/denylist-source-range:223.2.3.0/24
nginx.ingress.kubernetes.io/configuration-snippet: |
  proxy_set_header X-Pass $proxy_x_pass;
  rewrite ^/v6/(.*)/card/query http://foo.bar.com/v7/#!/card/query permanent;

namespace: test
spec:
ingressClassName: nginx
rules:

  • http:
    paths:

    • path: /showvar
      pathType: Prefix
      backend:
      service:
      name: svc-openresty
      port:
      number: 31080
      EOF

配置HTTPS服务转发到后端容器为HTTPS协议

Nginx Ingress Controller默认使用HTTP协议转发请求到后端业务容器。当您的业务容器为HTTPS协议时,可以通过使用注解nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"来使得Nginx Ingress Controller使用HTTPS协议转发请求到后端业务容器。


apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: backend-https
  annotations:
    #注意这里:必须指定后端服务为HTTPS服务。
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
  tls:
  - hosts:
    - 
    secretName: 
  rules:
  - host: 
    http:
      paths:
      - path: /
        backend:
          service:
            name: 
            port: 
              number: 
        pathType: ImplementationSpecific

配置域名支持正则化

在Kubernetes集群中,Ingress资源不支持对域名配置正则表达式,但是可以通过nginx.ingress.kubernetes.io/server-alias注解来实现。
创建Nginx Ingress,以正则表达式~^www.\d+.example.com为例。

cat <<-EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-regex
  namespace: default
  annotations:
    nginx.ingress.kubernetes.io/server-alias: '~^www\.\d+\.example\.com$, abc.example.com'
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /foo
        backend:
          service:
            name: http-svc1
            port:
              number: 80
        pathType: ImplementationSpecific
EOF

配置域名支持泛化

在Kubernetes集群中,Nginx Ingress资源支持对域名配置泛域名,例如,可配置*. ingress-regex.com泛域名。

cat <<-EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-regex
  namespace: default
spec:
  rules:
- host: *.ingress-regex.com
    http:
      paths:
      - path: /foo
        backend:
          service:
            name: http-svc1
            port:
              number: 80
        pathType: ImplementationSpecific
EOF

通过注解实现灰度发布

灰度发布功能可以通过设置注解来实现,为了启用灰度发布功能,需要设置注解nginx.ingress.kubernetes.io/canary: "true",通过不同注解可以实现不同的灰度发布功能:

nginx.ingress.kubernetes.io/canary-weight:设置请求到指定服务的百分比(值为0~100的整数)。

nginx.ingress.kubernetes.io/canary-by-header:基于Request Header的流量切分,当配置的hearder值为always时,请求流量会被分配到灰度服务入口;当hearder值为never时,请求流量不会分配到灰度服务;将忽略其他hearder值,并通过灰度优先级将请求流量分配到其他规则设置的灰度服务。

nginx.ingress.kubernetes.io/canary-by-header-value和nginx.ingress.kubernetes.io/canary-by-header:当请求中的hearder和header-value与设置的值匹配时,请求流量会被分配到灰度服务入口;将忽略其他hearder值,并通过灰度优先级将请求流量分配到其他规则设置的灰度服务。

nginx.ingress.kubernetes.io/canary-by-cookie:基于Cookie的流量切分,当配置的cookie值为always时,请求流量将被分配到灰度服务入口;当配置的cookie值为never时,请求流量将不会分配到灰度服务入口。
基于Header灰度(自定义header值):当请求Header为ack: alibaba时将访问灰度服务;其它Header将根据灰度权重将流量分配给灰度服务。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "20"
nginx.ingress.kubernetes.io/canary-by-header: "ack"
nginx.ingress.kubernetes.io/canary-by-header-value: "alibaba"

默认后端

nginx.ingress.kubernetes.io/default-backend: <svc name>

给后端传递header ns_clientip

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/configuration-snippet: |
      proxy_set_header ns-clientip $remote_addr;

或者是如下这种:

nginx.ingress.kubernetes.io/configuration-snippet: |
  more_set_headers "Request-Id: $req_id";

由于开启了realip,forwarded-for-header: "ns_clientip".
ns_clientip不再传给上游,这里再次指定传递

全局configmap 跨域

nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, OPTIONS" #Default: GET, PUT, POST, DELETE, PATCH, OPTIONS
nginx.ingress.kubernetes.io/cors-allow-headers: "Origin,User-Agent,Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With,token" Default: DNT,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization
nginx.ingress.kubernetes.io/cors-expose-headers: "" #Default: empty
nginx.ingress.kubernetes.io/cors-allow-origin: "http://wap.bbs.yingjiesheng.com, https://wap.bbs.yingjiesheng.com " # Default: *
nginx.ingress.kubernetes.io/cors-allow-credentials: "true" #Default: true
nginx.ingress.kubernetes.io/cors-max-age: "1728000" #Default: 1728000

main-snippet string ""
http-snippet string ""
server-snippet string ""
stream-snippet string ""
location-snippet string ""

otel-service-name string "nginx"
otel-service-name : "gateway"

添加自定义header
proxy-set-headers
https://kubernetes.github.io/ingress-nginx/examples/customization/custom-headers/

打开realip
enable-real-ip bool "false"
enable-real-ip: "true"

realip 的header头打开
use-forwarded-headers bool "false"
use-forwarded-headers: "true"

realip 的认证header头
forwarded-for-header string "X-Forwarded-For"
forwarded-for-header: ns_clientip

realip ip段
proxy-real-ip-cidr
proxy-real-ip-cidr: 192.168.0.0/16,10.244.0.0/16

将 remote address 附加到 X-Forwarded-For Header而不是替换它。
compute-full-forwarded-for bool "false"
compute-full-forwarded-for: "true"

全局ip封禁,优先于annotaion,或ingress规则
denylist-source-range []string []string{}
denylist-source-range: "223.2.4.0/24"

全局ip白名单,优先于denylist,如果设定那么只有此ip能访问,k8s内部不用ingress,所以内网ip不添加
可以和server的annotations配合再封禁某一段。nginx.ingress.kubernetes.io/denylist-source-range:223.2.2.0/24
whitelist-source-range []string []string{}
whitelist-source-range: "127.0.0.1,192.168.244.1,223.0.0.0/8"

全局ip封禁,优先于server白名单
block-cidrs []string ""
封禁223.2.4.0/24,如有多个用,分割
block-cidrs: "223.2.4.0/24"
https://nginx.org/en/docs/http/ngx_http_access_module.html#deny

全局ua封禁
block-user-agents []string ""
封禁含有spider 的ua,不区分大小写
block-user-agents: "~*spider"

全局封禁referer
block-referers []string ""
block-referers: "~*chinahr.com"

查看运行状态的ip
nginx-status-ipv4-whitelist []string "127.0.0.1"
http://127.0.0.1/nginx_status/

Posted in 技术.


k8s_安装8_UI_Dashboard

八、 dashkoard

kubernetes/dashboard

Dashboard 是基于网页的 Kubernetes 用户界面。 你可以使用 Dashboard 将容器应用部署到 Kubernetes 集群中,也可以对容器应用排错,还能管理集群资源。 你可以使用 Dashboard 获取运行在集群中的应用的概览信息,也可以创建或者修改 Kubernetes 资源 (如 Deployment,Job,DaemonSet 等等)。 例如,你可以对 Deployment 实现弹性伸缩、发起滚动升级、重启 Pod 或者使用向导创建新的应用。

官方文档:https://kubernetes.io/zh-cn/docs/tasks/access-application-cluster/web-ui-dashboard/
开源地址:https://github.com/kubernetes/dashboard
版本兼容性确认:https://github.com/kubernetes/dashboard/releases

cert-manager

https://cert-manager.io/docs/installation/
wget --no-check-certificate https://github.com/cert-manager/cert-manager/releases/download/v1.13.1/cert-manager.yaml -O cert-manager-1.13.1.yaml
wget --no-check-certificate  https://github.com/cert-manager/cert-manager/releases/download/v1.13.2/cert-manager.yaml -O cert-manager-1.13.2.yaml

cat cert-manager-1.13.2.yaml|grep image:|sed -e 's/.*image: //'
"quay.io/jetstack/cert-manager-cainjector:v1.13.2"
"quay.io/jetstack/cert-manager-controller:v1.13.2"
"quay.io/jetstack/cert-manager-webhook:v1.13.2"

docker pull fishchen/cert-manager-controller:v1.13.2
docker pull quay.io/jetstack/cert-manager-webhook:v1.13.2
docker pull quay.io/jetstack/cert-manager-controller:v1.13.2
docker pull quay.nju.edu.cn/jetstack/cert-manager-controller:v1.13.2

quay.dockerproxy.com/
docker pull quay.dockerproxy.com/jetstack/cert-manager-controller:v1.13.1
docker pull quay.dockerproxy.com/jetstack/cert-manager-cainjector:v1.13.1
docker pull quay.dockerproxy.com/jetstack/cert-manager-webhook:v1.13.1

quay.io
docker pull quay.io/jetstack/cert-manager-cainjector:v1.13.1
docker pull quay.io/jetstack/cert-manager-controller:v1.13.1
docker pull quay.io/jetstack/cert-manager-webhook:v1.13.1

quay.nju.edu.cn
docker pull quay.nju.edu.cn/jetstack/cert-manager-cainjector:v1.13.1
docker pull quay.nju.edu.cn/jetstack/cert-manager-controller:v1.13.1
docker pull quay.nju.edu.cn/jetstack/cert-manager-webhook:v1.13.1

docker tag quay.dockerproxy.com/jetstack/cert-manager-cainjector:v1.13.1 repo.k8s.local/quay.io/jetstack/cert-manager-cainjector:v1.13.1
docker tag quay.nju.edu.cn/jetstack/cert-manager-webhook:v1.13.1  repo.k8s.local/quay.io/jetstack/cert-manager-webhook:v1.13.1
docker tag quay.io/jetstack/cert-manager-controller:v1.13.1  repo.k8s.local/quay.io/jetstack/cert-manager-controller:v1.13.1

docker push repo.k8s.local/quay.io/jetstack/cert-manager-cainjector:v1.13.1
docker push repo.k8s.local/quay.io/jetstack/cert-manager-webhook:v1.13.1
docker push repo.k8s.local/quay.io/jetstack/cert-manager-controller:v1.13.1
导入省略,可以参见harbor安装
docker pull ...
docker tag ...
docker push ...
docker images

准备yaml文件

cp cert-manager-1.13.1.yaml  cert-manager-1.13.1.org.yaml

sed -n 's/quay\.io/repo.k8s.local\/quay\.io/p'  cert-manager-1.13.1.yaml
sed -i 's/quay\.io/repo.k8s.local\/quay\.io/'  cert-manager-1.13.1.yaml
cat cert-manager-1.13.1.yaml|grep image:|sed -e 's/.*image: //'

kubectl apply -f cert-manager-1.13.1.yaml

customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/clusterissuers.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/issuers.cert-manager.io created
customresourcedefinition.apiextensions.k8s.io/orders.acme.cert-manager.io created
serviceaccount/cert-manager-cainjector created
serviceaccount/cert-manager created
serviceaccount/cert-manager-webhook created
configmap/cert-manager created
configmap/cert-manager-webhook created
clusterrole.rbac.authorization.k8s.io/cert-manager-cainjector created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-issuers created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-certificates created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-orders created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-challenges created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim created
clusterrole.rbac.authorization.k8s.io/cert-manager-cluster-view created
clusterrole.rbac.authorization.k8s.io/cert-manager-view created
clusterrole.rbac.authorization.k8s.io/cert-manager-edit created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-approve:cert-manager-io created
clusterrole.rbac.authorization.k8s.io/cert-manager-controller-certificatesigningrequests created
clusterrole.rbac.authorization.k8s.io/cert-manager-webhook:subjectaccessreviews created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-cainjector created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-issuers created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-clusterissuers created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-certificates created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-orders created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-challenges created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-ingress-shim created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-approve:cert-manager-io created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-controller-certificatesigningrequests created
clusterrolebinding.rbac.authorization.k8s.io/cert-manager-webhook:subjectaccessreviews created
role.rbac.authorization.k8s.io/cert-manager-cainjector:leaderelection created
role.rbac.authorization.k8s.io/cert-manager:leaderelection created
role.rbac.authorization.k8s.io/cert-manager-webhook:dynamic-serving created
rolebinding.rbac.authorization.k8s.io/cert-manager-cainjector:leaderelection created
rolebinding.rbac.authorization.k8s.io/cert-manager:leaderelection created
rolebinding.rbac.authorization.k8s.io/cert-manager-webhook:dynamic-serving created
service/cert-manager created
service/cert-manager-webhook created
deployment.apps/cert-manager-cainjector created
deployment.apps/cert-manager created
deployment.apps/cert-manager-webhook created
mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created

kubectl get pods –namespace cert-manager

NAME                                       READY   STATUS    RESTARTS   AGE
cert-manager-7f46fcb774-gfvjm              1/1     Running   0          14s
cert-manager-cainjector-55f76bd446-nxkrt   1/1     Running   0          14s
cert-manager-webhook-799cbdc68-4t9zw       1/1     Running   0          14s
准备yaml文件,并显示images地址

在控制节点
dashboard3.0.0-alpha0 需要cert-manager,用service或nodeport安装后无法显示页面 /api/v1/login/status 为404,要用ingress方式访问.

wget  --no-check-certificate  https://raw.githubusercontent.com/kubernetes/dashboard/v3.0.0-alpha0/charts/kubernetes-dashboard.yaml -O kubernetes-dashboard.yaml
cat kubernetes-dashboard.yaml |grep image:|sed -e 's/.*image: //'

docker.io/kubernetesui/dashboard-api:v1.0.0
docker.io/kubernetesui/dashboard-web:v1.0.0
docker.io/kubernetesui/metrics-scraper:v1.0.9
提取image名称,并在harobor 导入
cat kubernetes-dashboard.yaml |grep image:|awk -F'/' '{print $NF}'
dashboard-api:v1.0.0
dashboard-web:v1.0.0
metrics-scraper:v1.0.9

#导入省略,可以参见harbor安装
docker pull ...
docker tag ...
docker push ...
docker images
导入harbor私仓后,替换docker.io为私仓repo.k8s.local 地址

如果拉取缓慢,Pulling fs layer,没有私仓可以用阿里的
registry.aliyuncs.com/google_containers/

cp kubernetes-dashboard.yaml kubernetes-dashboard.org.yaml
sed -n 's/docker\.io\/kubernetesui/repo.k8s.local\/google_containers/p'  kubernetes-dashboard.yaml
sed -i 's/docker\.io\/kubernetesui/repo.k8s.local\/google_containers/'  kubernetes-dashboard.yaml
cat  kubernetes-dashboard.yaml|grep -C2 image:
开始安装kubernetes-dashboard

kubectl apply -f kubernetes-dashboard.yaml

namespace/kubernetes-dashboard created
serviceaccount/kubernetes-dashboard created
secret/kubernetes-dashboard-csrf created
secret/kubernetes-dashboard-key-holder created
configmap/kubernetes-dashboard-settings created
role.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrole.rbac.authorization.k8s.io/kubernetes-dashboard created
rolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
clusterrolebinding.rbac.authorization.k8s.io/kubernetes-dashboard created
service/kubernetes-dashboard-web created
service/kubernetes-dashboard-api created
service/kubernetes-dashboard-metrics-scraper created
ingress.networking.k8s.io/kubernetes-dashboard created
deployment.apps/kubernetes-dashboard-api created
deployment.apps/kubernetes-dashboard-web created
deployment.apps/kubernetes-dashboard-metrics-scraper created
error: resource mapping not found for name: "selfsigned" namespace: "kubernetes-dashboard" from "kubernetes-dashboard.yaml": no matches for kind "Issuer" in version "cert-manager.io/v1"
ensure CRDs are installed first
查看状态
kubectl get pod -n kubernetes-dashboard -o wide
NAME                                                    READY   STATUS             RESTARTS   AGE
kubernetes-dashboard-api-6bfd48fcf6-njg9s               0/1     ImagePullBackOff   0          12m
kubernetes-dashboard-metrics-scraper-7d8c76dc88-6rn2w   0/1     ImagePullBackOff   0          12m
kubernetes-dashboard-web-7776cdb89f-jdwqt               0/1     ImagePullBackOff   0          12m
没有查到日志
kubectl logs kubernetes-dashboard-api-6bfd48fcf6-njg9s
Error from server (NotFound): pods "kubernetes-dashboard-api-6bfd48fcf6-njg9s" not found
指定namespace查看日志
kubectl describe pods/kubernetes-dashboard-api-6bfd48fcf6-njg9s -n kubernetes-dashboard
Name:             kubernetes-dashboard-api-6bfd48fcf6-njg9s
Namespace:        kubernetes-dashboard
Priority:         0
Service Account:  kubernetes-dashboard
Node:             node01.k8s.local/192.168.244.5
Start Time:       Tue, 17 Oct 2023 13:24:23 +0800
Labels:           app.kubernetes.io/component=api
                  app.kubernetes.io/name=kubernetes-dashboard-api
                  app.kubernetes.io/part-of=kubernetes-dashboard
                  app.kubernetes.io/version=v1.0.0
                  pod-template-hash=6bfd48fcf6

Normal   Scheduled  39m                    default-scheduler  Successfully assigned kubernetes-dashboard/kubernetes-dashboard-api-6bfd48fcf6-njg9s to node01.k8s.local
  Normal   Pulling    38m (x4 over 39m)      kubelet            Pulling image "repo.k8s.local/kubernetesui/dashboard-api:v1.0.0"
  Warning  Failed     38m (x4 over 39m)      kubelet            Failed to pull image "repo.k8s.local/kubernetesui/dashboard-api:v1.0.0": failed to pull and unpack image "repo.k8s.local/kubernetesui/dashboard-api:v1.0.0": failed to resolve reference "repo.k8s.local/kubernetesui/dashboard-api:v1.0.0": unexpected status from HEAD request to https://repo.k8s.local/v2/kubernetesui/dashboard-api/manifests/v1.0.0: 401 Unauthorized
  Warning  Failed     38m (x4 over 39m)      kubelet            Error: ErrImagePull
  Warning  Failed     37m (x6 over 39m)      kubelet            Error: ImagePullBackOff
  Normal   BackOff    4m29s (x150 over 39m)  kubelet            Back-off pulling image "repo.k8s.local/kubernetesui/dashboard-api:v1.0.0"
修正后重新安装

repo.k8s.local/kubernetesui/dashboard-api:v1.0.0 应为 repo.k8s.local/google_containers/dashboard-api:v1.0.0

kubectl delete -f kubernetes-dashboard.yaml
kubectl apply -f kubernetes-dashboard.yaml

运行正常

kubectl get pod -n kubernetes-dashboard  -o wide
NAME                                                    READY   STATUS    RESTARTS   AGE
kubernetes-dashboard-api-5fcfcfd7b-nlrnh                1/1     Running   0          15s
kubernetes-dashboard-metrics-scraper-585685f868-f7g5j   1/1     Running   0          15s
kubernetes-dashboard-web-57bd66fd9f-hbc62               1/1     Running   0          15s

kubectl describe pods/kubernetes-dashboard-api-5fcfcfd7b-nlrnh -n kubernetes-dashboard

查看Service暴露端口,我们使用这个端口进行访问:
kubectl get svc -n kubernetes-dashboard
NAME                                   TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
kubernetes-dashboard-api               ClusterIP   10.96.175.209   <none>        9000/TCP   14s
kubernetes-dashboard-metrics-scraper   ClusterIP   10.96.69.44     <none>        8000/TCP   14s
kubernetes-dashboard-web               ClusterIP   10.96.49.99     <none>        8000/TCP   14s
ClusterIP先行测试
curl http://10.96.175.209:9000/api/v1/login/status
{
 "tokenPresent": false,
 "headerPresent": false,
 "httpsMode": true,
 "impersonationPresent": false,
 "impersonatedUser": ""
}
curl http://10.96.49.99:8000/
<!--
Copyright 2017 The Kubernetes Authors.
创建kubernetes-dashboard管理员角色

默认账号kubernetes-dashboard权限过小

cat > dashboard-svc-account.yaml << EOF
apiVersion: v1
kind: ServiceAccount
metadata:
  name: dashboard-admin
  namespace: kubernetes-dashboard
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1      #需要修改的地方
metadata:
  name: dashboard-admin
subjects:
  - kind: ServiceAccount
    name: dashboard-admin
    namespace: kubernetes-dashboard
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io
EOF

kubectl apply -f dashboard-svc-account.yaml 
serviceaccount/dashboard-admin created
clusterrolebinding.rbac.authorization.k8s.io/dashboard-admin created
Kubernetes服务帐户没有token?

kubectl get secret -n kubernetes-dashboard|grep admin|awk ‘{print $1}’
之前secret中查token已不适用

之前的版本在创建serviceAccount之后会自动生成secret,可以通过kubectl get secret -n kube-system命令查看,现在需要多执行一步:
自Kubernetes版本1.22以来,默认情况下不会为ServiceAccounts生成令牌,需运行生成token,这种方式创建是临时的

kubectl create token dashboard-admin --namespace kubernetes-dashboard
eyJhbGciOiJSUzI1NiIsImtpZCI6Ik9EWUpmSzcyLUdzRlJnQWNhdHpOYWhNX0E4RDZ6Zl9id0JMcXZyMng5bkUifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzAwNTM4ODQzLCJpYXQiOjE3MDA1MzUyNDMsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJkYXNoYm9hcmQtYWRtaW4iLCJ1aWQiOiI3ZmUwYjFiZi05ZDhlLTRjOGItYWEzMy0xZWU3ZDU2YjE2NjUifX0sIm5iZiI6MTcwMDUzNTI0Mywic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmVybmV0ZXMtZGFzaGJvYXJkOmRhc2hib2FyZC1hZG1pbiJ9.cUGX77qAdY7Mqo3tPbWgcCLD2zmRoNUSlFG1EHlCRBwiA7ffL1PGbOHazE6eTmLrRo5if6nm9ILAK1Mv4Co2woOEW8qIJBVXClpZomvkj7BC2bGd-0X5W1s87CnEX7RnKcBqFVcP6zJY_ycLy1o9X9g4Y1wtMm8mptBgos5xmVAb8HecTgOWHt80W736K3WSB9ovuoAGVZe7-ahQ7DX8WJ_qYqbEE5v9laqYBIddcoJtfAYf8U8yaW-MQsJq46xp_sxU164WDozw_sSe4PIxHHqaG4tulJy3J2fn6D_0xbC8fupX3l8FPLcPQm1rWMFGPjsLhU8i_0ihnvyEmvsA6w

#默认账号
kubectl create token kubernetes-dashboard --namespace kubernetes-dashboard
eyJhbGciOiJSUzI1NiIsImtpZCI6Ik9EWUpmSzcyLUdzRlJnQWNhdHpOYWhNX0E4RDZ6Zl9id0JMcXZyMng5bkUifQ.eyJhdWQiOlsiaHR0cHM6Ly9rdWJlcm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWwiXSwiZXhwIjoxNzAwNTM5MzgwLCJpYXQiOjE3MDA1MzU3ODAsImlzcyI6Imh0dHBzOi8va3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVyLmxvY2FsIiwia3ViZXJuZXRlcy5pbyI6eyJuYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsInNlcnZpY2VhY2NvdW50Ijp7Im5hbWUiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsInVpZCI6ImU2NWUzODRhLTI5ZDYtNGYwYy04OGI0LWJlZWVkYmRhODMxNiJ9fSwibmJmIjoxNzAwNTM1NzgwLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZXJuZXRlcy1kYXNoYm9hcmQ6a3ViZXJuZXRlcy1kYXNoYm9hcmQifQ.rpE8aVSVWGcydSJy_QcCg6LjdxPvE2M45AspWqC-u406HSznOby1cTvpa9c7scQ7KooyrjSdlzW-1JVd4U6aFSt8sKQLmLXSTUoGi7ACkI105wTGUU4WQmB5CaPynPC68hhrNPTrEXvM4fichCDykp2hWaVCKOwSQPU-cMsCrIeg-Jqeikckdbpfr7m5XDW8_ydb-_X49hwDVqJeA8eJ5Qn-qlkts8Lj3m3rWjVTKlVeMJARR6LCbZUFZ3uwmOFyUzIX0UDKUHGktt5-k33LbLMMpvKKRzhwfu9o5WSTQdvFux1EpVskYxtjpsyKW_PEwcz6UzxvaLwToxV4uDq5_w

# 可以加上 --duration 参数设置时间 kubectl create token account -h查看具体命令
kubectl create token dashboard-admin --namespace kubernetes-dashboard --duration 10h
dashboard暴露方式

部署 ingress
kube proxy 代理service ,无法访问api会显示白板
service NodePort 类型,无法访问api会显示白板

需要通过ingress,才能正常显示页面
修改kind: Ingress,将localhost去掉
kubectl edit Ingress kubernetes-dashboard -n kubernetes-dashboard

    #- host: localhost
     - http:

使用ingress的端口访口

curl http://127.0.0.1:30180/

curl http://127.0.0.1:30180/api/v1/login/status
{
 "tokenPresent": false,
 "headerPresent": false,
 "httpsMode": true,
 "impersonationPresent": false,
 "impersonatedUser": ""
}

kubectl delete Ingress kubernetes-dashboard -n kubernetes-dashboard
kubectl apply -f kubernetes-dashboard.yaml

Kubernetes Dashboard 认证时间延长

默认的Token失效时间是900秒,也就是15分钟,这意味着你每隔15分钟就要认证一次。
改成12小时。 – –token-ttl=43200
kubectl edit deployment kubernetes-dashboard-api -n kubernetes-dashboard

          args:
            - --enable-insecure-login
            - --namespace=kubernetes-dashboard
            - --token-ttl=43200
kubectl get pod -n kubernetes-dashboard  -o wide
NAME                                                    READY   STATUS    RESTARTS   AGE   IP             NODE               NOMINATED NODE   READINESS GATES
kubernetes-dashboard-api-55cf847b6b-7sctx               1/1     Running   0          20h   10.244.2.251   node02.k8s.local   <none>           <none>
kubernetes-dashboard-metrics-scraper-585685f868-hqgpc   1/1     Running   0          40h   10.244.1.254   node01.k8s.local   <none>           <none>
kubernetes-dashboard-web-57bd66fd9f-pghct               1/1     Running   0          40h   10.244.1.253   node01.k8s.local   <none>           <none>

kubectl delete pod kubernetes-dashboard-api-55cf847b6b-7sctx -n kubernetes-dashboard

使用域名

本机host中添加域名
dashboard.k8s.local

kubectl edit Ingress kubernetes-dashboard -n kubernetes-dashboard

  rules:
    #- host: 127.0.0.1 #Invalid value: "127.0.0.1": must be a DNS name, not an IP address
    #- host: localhost
     - host: dashboard.k8s.local
       http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: kubernetes-dashboard-web
                port:
                  #number: 8000
                  name: web

curl -k -H "Host:dashboard.k8s.local" http://10.96.49.99:8000/

    - host: dashboard.k8s.local
      http:

kubectl apply -f kubernetes-dashboard.yaml

metrics-server 安装

metrics-server 采集node 和pod 的cpu/mem,数据存在容器本地,不做持久化。这些数据的使用场景有 kubectl top 和scheduler 调度、hpa 弹性伸缩,以及原生的dashboard 监控数据展示。
metrics-server 和prometheus 没有半毛钱关系。 也没有任何数据或者接口互相依赖关系。

Error scraping node metrics: the server could not find the requested resource (get nodes.metrics.k8s.io

https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/metrics-server

wget --no-check-certificate   https://github.com/kubernetes-sigs/metrics-server/releases/download/v0.6.3/components.yaml -O metrics-server-0.6.3.yaml

在deploy中,spec.template.containers.args字段中加上--kubelet-insecure-tls选项,表示不验证客户端证书

cat metrics-server-0.6.3.yaml|grep image:
image: registry.k8s.io/metrics-server/metrics-server:v0.6.3

docker pull registry.aliyuncs.com/google_containers/metrics-server:v0.6.3
docker tag registry.aliyuncs.com/google_containers/metrics-server:v0.6.3  repo.k8s.local/registry.k8s.io/metrics-server/metrics-server:v0.6.3
docker push repo.k8s.local/registry.k8s.io/metrics-server/metrics-server:v0.6.3

sed -n "/image:/{s/image: /image: repo.k8s.local\//p}" metrics-server-0.6.3.yaml
sed -i "/image:/{s/image: /image: repo.k8s.local\//}" metrics-server-0.6.3.yaml

kubectl top nodes

kubectl apply -f metrics-server-0.6.3.yaml

kubectl get pods -n=kube-system |grep metrics
metrics-server-8fc7dd595-n2s6b               1/1     Running   6 (9d ago)      16d

kubectl api-versions|grep metrics
metrics.k8s.io/v1beta1

#top会比dashboard中看到的要高
kubectl top pods
kubectl top nodes
NAME                 CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
master01.k8s.local   145m         3%     1490Mi          38%       
node01.k8s.local     54m          2%     1770Mi          46%       
node02.k8s.local     63m          3%     2477Mi          64%       

kubectl -n kube-system describe pod metrics-server-8fc7dd595-n2s6b 
kubectl logs metrics-server-8fc7dd595-n2s6b -n kube-system

kubectl describe  pod kube-apiserver-master01.k8s.local -n kube-system
  Type     Reason     Age                   From     Message
  ----     ------     ----                  ----     -------
  Warning  Unhealthy  35m (x321 over 10d)   kubelet  Liveness probe failed: HTTP probe failed with statuscode: 500
  Warning  Unhealthy  34m (x1378 over 10d)  kubelet  Readiness probe failed: HTTP probe failed with statuscode: 500
error: Metrics API not available

重新执行yaml
kubectl top pods
kubectl apply -f metrics-server-0.6.3.yaml

kubectl -n kube-system describe pod metrics-server-8fc7dd595-lz5kz

Posted in 安装k8s/kubernetes.

Tagged with , .


k8s_安装7_存储

七、存储

持久化存储pv,pvc
k8s存储支持多种模式:

  • 本地存储:hostPath/emptyDir
  • 传递网络存储:iscsi/nfs
  • 分布式网络存储:glusterfs/rbd/cephfs等
  • 云存储:AWS,EBS等
  • k8s资源: configmap,secret等

emptyDir 数据卷

临时数据卷,与pod生命周期绑定在一起,pod删除了,数据卷也会被删除。
作用:持久化,随着pod的生命周期而存在(删除容器不代表pod被删除了,不影响数据)
多个pod之间不能通信,同一pod中的容器可以共享数据

spec:
  containers:
  - name: nginx1
    image: nginx
    ports:
    - name: http
      containerPort: 80
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html/
  - name: nginx2
    image: nginx
    volumeMounts:
    - name: html
      mountPath: /data/
    command: ['/bin/bash','-c','while true;do echo $(date) >> /data/index.html;sleep 10;done']
  volumes:
  - name: html
    emptyDir: {}

hostPath 数据卷

实现同一个node节点的多个pod实现数据共享
也可以设置type字段,支持的类型有File、FileOrCreate、 Directory、DirectoryOrCreate、Socket、CharDevice和BlockDevice。

spec:
  containers:
  - name: nginx1
    image: nginx
    ports:
    - name: http
      containerPort: 80
    volumeMounts:        
    - name: html    ##使用的存储卷名称,如果跟下面volume字段name值相同,则表示使用volume的这个存储卷
      mountPath: /usr/share/nginx/html/   ##挂载至容器中哪个目录
      readOnly: false     #读写挂载方式,默认为读写模式false
  volumes: 
  - name: html     #存储卷名称
    hostPath:      
      path: /data/pod/volume   #在宿主机上目录的路径
      type: DirectoryOrCreate  #定义类型,这表示如果宿主机没有此目录则会自动创建

NFS数据卷

不同的node节点的pod实现数据共享,但是存在单点故障

spec:
  containers:
  - name: nginx1
    image: nginx
    ports:
    - name: http
      containerPort: 80
    volumeMounts:        
    - name: html    ##使用的存储卷名称,如果跟下面volume字段name值相同,则表示使用volume的这个存储卷
      mountPath: /usr/share/nginx/html/   ##挂载至容器中哪个目录
      readOnly: false     #读写挂载方式,默认为读写模式false
  volumes: 
  - name: html     #存储卷名称
    nfs:      
      path: /nfs/k8s/data/volume   #在宿主机上目录的路径
      server: 192.168.244.6

NFS

NFS安装

k8s集群所有节点都需要安装NFS服务。本章节实验我们选用k8s的harbor节点作为NFS服务的server端.

nfs服务提供机安装

yum install -y nfs-utils rpcbind

创建nfs共享目录
mkdir -p /nfs/k8s/{yml,data,cfg,log,web}

#pv
mkdir -p /nfs/k8s/{spv_r1,spv_w1,spv_w2,dpv}  
mkdir -p /nfs/k8s/{spv_001,spv_002,spv_003,dpv}

#修改权限
chmod -R 777 /nfs/k8s
开始共享
#编辑export文件
/nfs/k8s:是共享的数据目录
*:               #表示任何人都有权限连接,当然也可以是一个网段,一个 IP,也可以是域名
rw:              #读写的权限
sync              #表示文件同时写入硬盘和内存
async             # 非同步模式,也就是每隔一段时间才会把内存的数据写入硬盘,能保证磁盘效率,但当异常宕机/断电时,会丢失内存里的数据
no_root_squash    # 当登录 NFS 主机使用共享目录的使用者是 root 时,其权限将被转换成为匿名使用者,通常它的 UID 与 GID,都会变成 nobody 身份
root_squash       # 跟no_root_squash相反,客户端上的root用户受到这些挂载选项的限制,被当成普通用户
all_squash        # 客户端上的所有用户在使用NFS共享目录时都被限定为一个普通用户
anonuid           # 上面的几个squash用于把客户端的用户限定为普通用户,而anouid用于限定这个普通用户的uid,这个uid与服务端的/etc/passwd文件相对应,如:anouid=1000 
                  # 比如我客户端用xiaoming这个用户去创建文件,那么服务端同步这个文件的时候,文件的属主会变成服务端的uid(1000)所对应的用户
anongid           # 同上,用于限定这个普通用户的gid

vi /etc/exports
/nfs/k8s/yml *(rw,no_root_squash,sync)  
/nfs/k8s/data *(rw,no_root_squash,sync)  
/nfs/k8s/cfg *(rw,no_root_squash,sync)  
/nfs/k8s/log *(rw,no_root_squash,sync)  
/nfs/k8s/web *(rw,no_root_squash,sync)  
/nfs/k8s/spv_001 *(rw,no_root_squash,sync)  
/nfs/k8s/spv_002 *(rw,no_root_squash,sync)  
/nfs/k8s/spv_003 *(rw,no_root_squash,sync)  
/nfs/k8s/dpv *(rw,no_root_squash,sync)  

#配置生效
exportfs -r
启动服务
#启动顺序,先启动rpc,再启动nfs
systemctl enable rpcbind
systemctl start rpcbind
systemctl status rpcbind
systemctl restart rpcbind

systemctl enable nfs
systemctl start nfs
systemctl status nfs
systemctl restart nfs

#查看相关信息
rpcinfo -p|grep nfs
    100003    3   tcp   2049  nfs
    100003    4   tcp   2049  nfs
    100227    3   tcp   2049  nfs_acl
    100003    3   udp   2049  nfs
    100003    4   udp   2049  nfs
    100227    3   udp   2049  nfs_acl

#查看
cat /var/lib/nfs/etab 
/nfs/k8s/log    *(rw,sync,wdelay,hide,nocrossmnt,secure,no_root_squash,no_all_squash,no_subtree_check,secure_locks,acl,no_pnfs,anonuid=65534,anongid=65534,sec=sys,rw,secure,no_root_squash,no_all_squash)
/nfs/k8s/cfg    *(rw,sync,wdelay,hide,nocrossmnt,secure,no_root_squash,no_all_squash,no_subtree_check,secure_locks,acl,no_pnfs,anonuid=65534,anongid=65534,sec=sys,rw,secure,no_root_squash,no_all_squash)
/nfs/k8s/data   *(rw,sync,wdelay,hide,nocrossmnt,secure,no_root_squash,no_all_squash,no_subtree_check,secure_locks,acl,no_pnfs,anonuid=65534,anongid=65534,sec=sys,rw,secure,no_root_squash,no_all_squash)
/nfs/k8s/yml    *(rw,sync,wdelay,hide,nocrossmnt,secure,no_root_squash,no_all_squash,no_subtree_check,secure_locks,acl,no_pnfs,anonuid=65534,anongid=65534,sec=sys,rw,secure,no_root_squash,no_all_squash)

#查看
showmount -e 
Export list for 192.168.244.6:
Export list for repo.k8s.local:
/nfs/k8s/log  *
/nfs/k8s/cfg  *
/nfs/k8s/data *
/nfs/k8s/yml  *
客户端操作
安装服务

yum -y install nfs-utils

查看

showmount -e 192.168.244.6
Export list for 192.168.244.6:
/nfs/k8s/log
/nfs/k8s/cfg

/nfs/k8s/data
/nfs/k8s/yml

/nfs/k8s/web *

工作节点创建挂载点

mkdir -p /data/k8s/{yml,data,cfg,log,web}

systemctl enable rpcbind
systemctl start rpcbind
systemctl status rpcbind

手动挂载
mount 192.168.244.6:/nfs/k8s/yml /data/k8s/yml
mount 192.168.244.6:/nfs/k8s/data /data/k8s/data
mount 192.168.244.6:/nfs/k8s/cfg /data/k8s/cfg
mount 192.168.244.6:/nfs/k8s/log /data/k8s/log

df -Th | grep /data/k8s/
192.168.244.6:/nfs/k8s/data nfs4       26G  8.9G   18G  35% /data/k8s/data
192.168.244.6:/nfs/k8s/cfg  nfs4       26G  8.9G   18G  35% /data/k8s/cfg
192.168.244.6:/nfs/k8s/log  nfs4       26G  8.9G   18G  35% /data/k8s/log
192.168.244.6:/nfs/k8s/yml  nfs4       26G  8.9G   18G  35% /data/k8s/yml

touch /data/k8s/cfg/test

#加入启动
# 追加插入以下内容
cat >> /etc/fstab <<EOF
192.168.244.6:/nfs/k8s/yml /data/k8s/yml nfs rw,rsize=8192,wsize=8192,soft,intr 0 0
192.168.244.6:/nfs/k8s/data /data/k8s/data nfs rw,rsize=8192,wsize=8192,soft,intr 0 0
192.168.244.6:/nfs/k8s/cfg /data/k8s/cfg nfs rw,rsize=8192,wsize=8192,soft,intr 0 0
192.168.244.6:/nfs/k8s/log /data/k8s/log nfs rw,rsize=8192,wsize=8192,soft,intr 0 0
EOF

PV与PVC的简介

PV(PersistentVolume)是持久化卷的意思,是对底层的共享存储的一种抽象,管理员已经提供好的一块存储。在k8s集群中,PV像Node一样,是一个资源。
PV类型:NFS iSCSI CephFS Glusterfs HostPath AzureDisk 等等
PVC(PersistentVolumeClaim)是持久化卷声明的意思,是用户对于存储需求的一种声明。PVC对于PV就像Pod对于Node一样,Pod可以申请CPU和Memory资源,而PVC也可以申请PV的大小与权限。
有了PersistentVolumeClaim,用户只需要告诉Kubernetes需要什么样的存储资源,而不必关心真正的空间从哪里分配,如何访问等底层细节信息。这些Storage Provider的底层信息交给管理员来处理,只有管理员才应该关心创建PersistentVolume的细节信息

PVC和PV是一一对应的。
PV和StorageClass不受限于Namespace,PVC受限于Namespace,Pod在引用PVC时同样受Namespace的限制,只有相同Namespace中的PVC才能挂载到Pod内。
虽然PersistentVolumeClaims允许用户使用抽象存储资源,但是PersistentVolumes对于不同的问题,用户通常需要具有不同属性(例如性能)。群集管理员需要能够提供各种PersistentVolumes不同的方式,而不仅仅是大小和访问模式,而不会让用户了解这些卷的实现方式。对于这些需求,有StorageClass 资源。
StorageClass为管理员提供了一种描述他们提供的存储的“类”的方法。 不同的类可能映射到服务质量级别,或备份策略,或者由群集管理员确定的任意策略。 Kubernetes本身对于什么类别代表是不言而喻的。 这个概念有时在其他存储系统中称为“配置文件”。
一个PVC只能绑定一个PV,一个PV只能对应一种后端存储,一个Pod可以使用多个PVC,一个PVC也可以给多个Pod使用

生命周期

Provisioning ——-> Binding ——–>Using——>Releasing——>Recycling

供应准备Provisioning
静态供给 Static Provision

集群管理员通过手动方式先创建好应用所需不同大小,是否读写的PV,在创建PVC时云匹配相近的。
在创建PVC时会根据需求属性(大小,只读等)匹配最合适的PV,有一定随机,可以定义回收时清除PV中数据。
如创建一个6G的存储,不会匹配5G的PV,会匹配比6G大的PV,如10G的PV.

如何将PVC绑定到特定的PV上?给PV打上一个label,然后让PVC去匹配这个label即可,
方式一,在 PVC 的 YAML 文件中指定 spec.volumeName 字段
方式二,spec.selector.matchLabels.pv

动态供给 Dynamic Provision

当管理员创建的静态PV都不匹配用户的PVC,集群可能会尝试为PVC动态配置卷,实现了存储卷的按需创建,不需要提前创建 PV,此配置基于StorageClasse.
用户创建了PVC需求,然后由组件云动态创建的PV,PVC必须请求一个类,并且管理员必须已创建并配置该类才能进行动态配置。 要求该类的声明有效地为自己禁用动态配置。

Binding 绑定

用户创建pvc并指定需要的资源和访问模式。在找到可用pv之前,pvc会保持未绑定状态。

Using 使用

用户可在pod中像volume一样使用pvc。

Releasing 释放

用户删除pvc来回收存储资源,pv将变成“released”状态。由于还保留着之前的数据,这些数据需要根据不同的策略来处理,否则这些存储资源无法被其他pvc使用。

回收Recycling

pv可以设置三种回收策略:保留(Retain),回收(Recycle)和删除(Delete)。

  • 保留策略Retain :允许人工处理保留的数据。
  • 删除策略Delete :将删除pv和外部关联的存储资源,需要插件支持。
  • 回收策略Recycle :将执行清除操作,之后可以被新的pvc使用,需要插件支持。
    PVC 只能和 Available 状态的 PV 进行绑定
PV卷阶段状态

Available – 资源尚未被pvc使用
Bound – 卷已经被绑定到pvc了
Released – pvc被删除,卷处于释放状态,但未被集群回收。
Failed – 卷自动回收失败

StorageClass运行原理及部署流程

  • 1.自动创建的 PV 以${namespace}-${pvcName}-${pvName}这样的命名格式创建在 NFS 服务器上的共享数据目录中

  • 2.而当这个 PV 被回收后会以archieved-${namespace}-${pvcName}-${pvName}这样的命名格式存在 NFS 服务器上
    StorageClass一旦被创建,就无法修改,如需修改,只能删除重建。

配置说明:

capacity 指定 PV 的容量为 1G。
accessModes 指定访问模式为 ReadWriteOnce,支持的访问模式有:

    ReadWriteOnce – PV 能以 read-write 模式 mount 到单个节点。
    ReadOnlyMany – PV 能以 read-only 模式 mount 到多个节点。
    ReadWriteMany – PV 能以 read-write 模式 mount 到多个节点。

 persistentVolumeReclaimPolicy 指定当 PV 的回收策略为 Recycle,支持的策略有:

    Retain – 需要管理员手工回收。
    Recycle – 清除 PV 中的数据,效果相当于执行 rm -rf /thevolume/*。目前只支持NFS和hostPath支持此操作
    Delete – 删除 Storage Provider 上的对应存储资源,仅部分支持云端存储系统支持,例如 AWS EBS、GCE PD、Azure
    Disk、OpenStack Cinder Volume 等。

storageClassName 指定 PV 的 class 为 nfs。相当于为 PV 设置了一个分类,PVC 可以指定 class 申请相应 class 的 PV。

静态创建PV卷

# 注意命名和域名一样,只充许小写字母数字-.
# 1g大小,多节点只读,保留数据
# cat nfs-pv001.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-spv001
  labels:
    pv: nfs-spv001
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadOnlyMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
    path: /nfs/k8s/spv_001
    server: 192.168.244.6

# 2g大小,单节点读写,清除数据
# cat nfs-pv002.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-spv002
  labels:
    pv: nfs-spv002
spec:
  capacity:
    storage: 2Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: nfs
  nfs:
    path: /nfs/k8s/spv_002
    server: 192.168.244.6

# 3g大小,多节点读写,保留数据
pv上可设nfs参数,pod中不可以
# cat nfs-pv003.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-spv003
  labels:
    pv: nfs-spv003
spec:
  capacity:
    storage: 3Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  mountOptions:
    - hard
    - intr
    - timeo=60
    - retrans=2
    - noresvport
    - nfsvers=4.1
  nfs:
    path: /nfs/k8s/spv_003
    server: 192.168.244.6
pv生效
kubectl apply -f nfs-pv001.yaml
persistentvolume/nfs-spv001 created
kubectl apply -f nfs-pv002.yaml
persistentvolume/nfs-spv002 created
kubectl apply -f nfs-pv003.yaml
persistentvolume/nfs-spv003 created

kubectl get pv
NAME          CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
nfs-spv001r   1Gi        ROX            Retain           Available           nfs                     36s
nfs-spv002    2Gi        RWO            Recycle          Available           nfs                     21s
nfs-spv003    3Gi        RWX            Retain           Available           nfs                     18s
删pv

kubectl delete -f nfs-pv001.yaml

回收pv
#,当pv标记为Recycle时,删除pvc,pv STATUS 为Released/Failed ,删除claimRef段后恢复 Available
kubectl edit pv nfs-spv002
  claimRef:
    apiVersion: v1
    kind: PersistentVolumeClaim
    name: nfs-pvc002
    namespace: default
    resourceVersion: "835243"
    uid: 3bd83223-fd84-4b53-a0db-1a5f62e433fa

kubectl patch pv nfs-spv002 –patch ‘{"spec": {"claimRef":null}}’

创建 PVC

### 1G大小,只读,指定pv
# cat nfs-pvc1.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc001
spec:
  accessModes:
    - ReadOnlyMany
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs
  selector:
    matchLabels:
      pv: nfs-spv001

# 指定pv,注意pvc空间比pv小,实际创建已匹配到的pv为准
# cat nfs-pvc2.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc002
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs
  selector:
    matchLabels:
      pv: nfs-spv002

# 指定pv,注意pvc空间比pv小
# cat nfs-pvc3.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc003
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs
  selector:
    matchLabels:
      pv: nfs-spv003
生效pvc
kubectl apply -f nfs-pvc1.yaml
persistentvolumeclaim/nfs-pvc001 created
kubectl apply -f nfs-pvc2.yaml
persistentvolumeclaim/nfs-pvc002 created
kubectl apply -f nfs-pvc3.yaml
persistentvolumeclaim/nfs-pvc003 created

kubectl get pvc
NAME         STATUS   VOLUME       CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nfs-pvc001   Bound    nfs-spv001   1Gi        ROX            nfs            4s
nfs-pvc002   Bound    nfs-spv002   2Gi        RWO            nfs            5m3s
nfs-pvc003   Bound    nfs-spv003   3Gi        RWX            nfs            5m1s
删除pvc

kubectl delete -f nfs-pvc1.yaml

如果删pvc前先删了pv,pv STATUS:Terminating ,pvc 看不出异常.删除pvc后pv成功删除
没有pv前创建pvc,pvc STATUS Pending,创建pv后,pvc 正常
删除Recycle的pvc 后,在没回收前无法再使用相关pv

k8s进行pvc扩容

确认pv的回收策略,十分的重要!!!!!,确认回收策略必须为Retain不能是Delete不然解除绑定后PV就被删了,并修改pv大小

  • 1.根据pod找到绑定的pvc信息
    kubectl edit pods -n namespace podName
    在spec.volumes.persistentVolumeClaim.claimName可以找到我们需要的pvc名称

  • 2.根据PVC找到绑定的PV
    kubectl edit pvc -n namespace pvcName
    在spec.volumeName可以找到我们需要的pv名称

  • 3.确认pv信息,修改回收策略为Retain,修改pv大小,修改labels信息
    kubectl edit pv -n namespace nfs-spv001

修改spec.persistentVolumeReclaimPolicy为Retain
修改spec.capacity.storage的大小例如30Gi

或用patch
kubectl patch pv nfs-spv001 –type merge –patch ‘{"spec": {"capacity": {"storage": "1.3Gi"},"persistentVolumeReclaimPolicy":"Retain"}}’
kubectl get pv nfs-spv001

注意静态pvc 不能动态扩容
动态pvc可扩容,storageclass是否存在allowVolumeExpansion字段,不能缩容,需重启服务

k8s里面pod使用pv的大小跟pv的容量没有直接关系,而是跟挂载的文件系统大小有关系,pv的容量可以理解为给pv预留容量,当文件系统的可用容量<PV预留容量 时,pv创建失败,Pod也会Pending。
pv的实际使用量主要看挂载的文件系统大小,会出现nfs 存储类pv使用容量超出pv预留容量的情况。

基于NFS动态创建PV、PVC

https://kubernetes.io/docs/concepts/storage/storage-classes/
因为NFS不支持动态存储,所以我们需要借用这个存储插件nfs-client
https://github.com/kubernetes-retired/external-storage/tree/master/nfs-client/deploy

搭建StorageClass+NFS,大致有以下几个步骤:

  • 1).创建一个可用的NFS Serve
  • 2).创建Service Account.这是用来管控NFS provisioner在k8s集群中运行的权限
  • 3).创建StorageClass.负责建立PVC并调用NFS provisioner进行预定的工作,并让PV与PVC建立管理
  • 4).创建NFS provisioner.有两个功能,一个是在NFS共享目录下创建挂载点(volume),另一个则是建了PV并将PV与NFS的挂载点建立关联

nfs-provisioner-rbac.yaml 集群角色,普通角色,sa用户

wget https://github.com/kubernetes-retired/external-storage/raw/master/nfs-client/deploy/rbac.yaml -O nfs-provisioner-rbac.yaml
如果之前布署过,请先修改 namespace: default

# Set the subject of the RBAC objects to the current namespace where the provisioner is being deployed
$ NS=$(kubectl config get-contexts|grep -e "^\*" |awk '{print $5}')
$ NAMESPACE=${NS:-default}
$ sed -i'' "s/namespace:.*/namespace: $NAMESPACE/g" ./deploy/rbac.yaml ./deploy/deployment.yaml
$ kubectl create -f deploy/rbac.yaml
cat nfs-provisioner-rbac.yaml 
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io

StorageClass


cat > nfs-StorageClass.yaml << EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME'  #这里的名称要和provisioner配置文件中的环境变量PROVISIONER_NAME保持一致
parameters:
  archiveOnDelete: "false"
  type: nfs
reclaimPolicy: Retain
allowVolumeExpansion: true     #允许扩容
mountOptions:
  - hard
  - intr
  - timeo=60
  - retrans=2
  - noresvport
  - nfsvers=4.1
volumeBindingMode: Immediate     #pv和pvc绑定
EOF

请确认reclaimPolicy 是否为 Retain
请确认reclaimPolicy 是否为 Retain
请确认reclaimPolicy 是否为 Retain
重要事情三遍

在启用动态供应模式的情况下,一旦用户删除了PVC,与之绑定的PV也将根据其默认的回收策略“Delete”被删除。如果需要保留PV(用户数据),则在动态绑定成功后,用户需要将系统自动生成PV的回收策略从“Delete”改为“Retain”(保留)。
kubectl edit pv -n default nfs-spv001

使用如下命令可以修改pv回收策略:
kubectl patch pv -p ‘{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}’

provisioner 提供者 deployment.yaml

wget https://github.com/kubernetes-retired/external-storage/raw/master/nfs-client/deploy/deployment.yaml -O nfs-provisioner-deployment.yaml
namespace: default #与RBAC文件中的namespace保持一致
修改的参数包括NFS服务器所在的IP地址,共享的路径

cat nfs-provisioner-deployment.yaml


apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs
            - name: NFS_SERVER
              value: 192.168.244.6
            - name: NFS_PATH
              value: /nfs/k8s/dpv
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.244.6
            path: /nfs/k8s/dpv

准备镜像

cat nfs-provisioner-deployment.yaml  |grep image:|sed -e 's/.*image: //'
quay.io/external_storage/nfs-client-provisioner:latest

docker pull quay.io/external_storage/nfs-client-provisioner:latest
docker tag quay.io/external_storage/nfs-client-provisioner:latest repo.k8s.local/google_containers/nfs-client-provisioner:latest
docker push repo.k8s.local/google_containers/nfs-client-provisioner:latest
docker rmi quay.io/external_storage/nfs-client-provisioner:latest

替换镜像地址

cp nfs-provisioner-deployment.yaml nfs-provisioner-deployment.org.yaml
sed -n '/image:/{s/quay.io\/external_storage/repo.k8s.local\/google_containers/p}' nfs-provisioner-deployment.yaml
sed -i '/image:/{s/quay.io\/external_storage/repo.k8s.local\/google_containers/}' nfs-provisioner-deployment.yaml
cat nfs-provisioner-deployment.yaml  |grep image:

执行

kubectl apply -f nfs-provisioner-rbac.yaml 
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created

#kubectl delete -f nfs-StorageClass.yaml
kubectl apply -f nfs-StorageClass.yaml
storageclass.storage.k8s.io/managed-nfs-storage created

kubectl apply -f nfs-provisioner-deployment.yaml 
deployment.apps/nfs-client-provisioner created

#查看sa
kubectl get sa

#查看storageclass
kubectl get sc

#查看deploy控制器
kubectl get deploy

#查看pod
kubectl get pod

[root@master01 k8s]# kubectl get sa
NAME                     SECRETS   AGE
default                  0         8d
nfs-client-provisioner   0         2m42s
[root@master01 k8s]# kubectl get sc
NAME                  PROVISIONER      RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
managed-nfs-storage   fuseim.pri/ifs   Delete          Immediate           false                  60s

注意 RECLAIMPOLICY 如果是Delete,数据会被删除

[root@master01 k8s]# kubectl get deploy
NAME                     READY   UP-TO-DATE   AVAILABLE   AGE
nfs-client-provisioner   1/1     1            1           30s
[root@master01 k8s]# kubectl get pod
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-54698bfc75-ld8fj   1/1     Running   0          37s

创建测试

#storageClassName 与nfs-StorageClass.yaml metadata.name保持一致
cat > test-pvc.yaml  << EOF
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
spec:
  storageClassName: managed-nfs-storage  
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 2Mi
EOF

#执行
kubectl apply -f test-pvc.yaml

kubectl get pvc
NAME         STATUS    VOLUME       CAPACITY   ACCESS MODES   STORAGECLASS          AGE
test-claim   Pending                                          managed-nfs-storage   14m

#可以看到一直是Pending状态

kubectl describe pvc test-claim
Name:          test-claim
Namespace:     default
StorageClass:  managed-nfs-storage
Status:        Pending
Volume:        
Labels:        <none>
Annotations:   volume.beta.kubernetes.io/storage-provisioner: fuseim.pri/ifs
               volume.kubernetes.io/storage-provisioner: fuseim.pri/ifs
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:      
Access Modes:  
VolumeMode:    Filesystem
Used By:       <none>
Events:
  Type    Reason                Age                 From                         Message
  ----    ------                ----                ----                         -------
  Normal  ExternalProvisioning  35s (x63 over 15m)  persistentvolume-controller  Waiting for a volume to be created either by the external provisioner 'fuseim.pri/ifs' or manually by the system administrator. If volume creation is delayed, please verify that the provisioner is running and correctly registered.

kubectl get pods
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-54698bfc75-ld8fj   1/1     Running   0          21m

kubectl logs nfs-client-provisioner-54698bfc75-ld8fj 
E1019 07:43:08.625350       1 controller.go:1004] provision "default/test-claim" class "managed-nfs-storage": unexpected error getting claim reference: selfLink was empty, can't make reference

Kubernetes 1.20及以后版本废弃了 selfLink 所致。
相关issue链接:https://github.com/kubernetes/kubernetes/pull/94397

解决方案一 (不适用1.26.6以上)

添加 – –advertise-address=192.168.244.4 后重启apiserver

vi /etc/kubernetes/manifests/kube-apiserver.yaml
  - command:
    - kube-apiserver
    - --feature-gates=RemoveSelfLink=false
    - --advertise-address=192.168.244.4
    - --allow-privileged=true

systemctl daemon-reload
systemctl restart kubelet

kubectl get nodes
The connection to the server 192.168.244.4:6443 was refused - did you specify the right host or port?

sed n '/insecure-port/s/^/#/gp' -i /etc/kubernetes/manifests/kube-apiserver.yaml
sed -e '/insecure-port/s/^/#/g' -i /etc/kubernetes/manifests/kube-apiserver.yaml

解决方案二 (适用1.20.x以上所有版本)

不用修改–feature-gates=RemoveSelfLink=false
修改 nfs-provisioner-deployment.yaml 镜像为nfs-subdir-external-provisioner:v4.0.2

原镜像
registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
国内加速
m.daocloud.io/gcr.io/k8s-staging-sig-storage/nfs-subdir-external-provisioner:v4.0.2

拉取推送私仓

docker pull m.daocloud.io/gcr.io/k8s-staging-sig-storage/nfs-subdir-external-provisioner:v4.0.2
docker tag m.daocloud.io/gcr.io/k8s-staging-sig-storage/nfs-subdir-external-provisioner:v4.0.2 repo.k8s.local/google_containers/nfs-subdir-external-provisioner:v4.0.2
docker push repo.k8s.local/google_containers/nfs-subdir-external-provisioner:v4.0.2
vi nfs-provisioner-deployment.yaml
image: repo.k8s.local/google_containers/nfs-subdir-external-provisioner:v4.0.2

#重新生效
kubectl apply -f nfs-provisioner-deployment.yaml 

kubectl get pods
NAME                                    READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-db4f6fb8-gnnbm   1/1     Running   0          16m

kubectl get pvc
NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
test-claim   Bound    pvc-16c63bbf-11c4-49aa-8289-7e4c64c78c2b   2Mi        RWX            managed-nfs-storage   99m

kubectl get pvc test-claim -o yaml | grep phase        
  phase: Bound

如果显示 phase 为 Bound,则说明已经创建 PV 且与 PVC 进行了绑定

kubectl describe pvc test-claim  
Normal  ProvisioningSucceeded  18m                fuseim.pri/ifs_nfs-client-provisioner-db4f6fb8-gnnbm_7f8d1cb0-c840-4198-afb0-f066f0ca86da  Successfully provisioned volume pvc-16c63bbf-11c4-49aa-8289-7e4c64c78c2b

可以看到创建了pv pvc-16c63bbf-11c4-49aa-8289-7e4c64c78c2b

在nfs目录下可以看自动创建的目录,
创建的目录命名方式为 namespace名称-pvc名称-pv名称,
PV 名称是随机字符串,所以每次只要不删除 PVC,那么 Kubernetes 中的与存储绑定将不会丢失,要是删除 PVC 也就意味着删除了绑定的文件夹,下次就算重新创建相同名称的 PVC,生成的文件夹名称也不会一致,因为 PV 名是随机生成的字符串,而文件夹命名又跟 PV 有关,所以删除 PVC 需谨慎
ll /nfs/k8s/dpv/default-test-claim-pvc-16c63bbf-11c4-49aa-8289-7e4c64c78c2b/

helm方式 安装

https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
$ helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
$ helm install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
    --set nfs.server=x.x.x.x \
    --set nfs.path=/exported/path

创建测试的 Pod 资源文件

创建一个用于测试的 Pod 资源文件 test-pod.yaml,文件内容如下:

cat > test-nfs-pod.yaml << EOF
kind: Pod
apiVersion: v1
metadata:
  name: test-nfs-pod
spec:
  containers:
  - name: test-pod
    image: busybox:latest
    command:
      - "/bin/sh"
    args:
      - "-c"
      - "touch /mnt/SUCCESS && exit 0 || exit 1"  ## 创建一个名称为"SUCCESS"的文件
    volumeMounts:
      - name: nfs-pvc
        mountPath: "/mnt"
  restartPolicy: "Never"
  volumes:
    - name: nfs-pvc
      persistentVolumeClaim:
        claimName: test-claim
EOF

kubectl apply -f test-nfs-pod.yaml

ll /nfs/k8s/dpv/default-test-claim-pvc-16c63bbf-11c4-49aa-8289-7e4c64c78c2b/
total 0
-rw-r--r--. 1 root root 0 Oct 19 17:23 SUCCESS

[root@master01 k8s]# kubectl get pv,pvc,pods
NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS          REASON   AGE
persistentvolume/nfs-spv001                                 1Gi        ROX            Retain           Bound    default/nfs-pvc001   nfs                            25h
persistentvolume/nfs-spv002                                 2Gi        RWO            Recycle          Bound    default/nfs-pvc002   nfs                            25h
persistentvolume/nfs-spv003                                 3Gi        RWX            Retain           Bound    default/nfs-pvc003   nfs                            25h
persistentvolume/pvc-16c63bbf-11c4-49aa-8289-7e4c64c78c2b   2Mi        RWX            Delete           Bound    default/test-claim   managed-nfs-storage            32m

NAME                               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
persistentvolumeclaim/nfs-pvc001   Bound    nfs-spv001                                 1Gi        ROX            nfs                   25h
persistentvolumeclaim/nfs-pvc002   Bound    nfs-spv002                                 2Gi        RWO            nfs                   25h
persistentvolumeclaim/nfs-pvc003   Bound    nfs-spv003                                 3Gi        RWX            nfs                   25h
persistentvolumeclaim/test-claim   Bound    pvc-16c63bbf-11c4-49aa-8289-7e4c64c78c2b   2Mi        RWX            managed-nfs-storage   116m

NAME                                        READY   STATUS      RESTARTS   AGE
pod/nfs-client-provisioner-db4f6fb8-gnnbm   1/1     Running     0          32m
pod/test-nfs-pod                            0/1     Completed   0          5m48s

pod执行完就退出,pvc状态是Completed,pv状态是Delete

测试写入空间限制

cat > test-nfs-pod1.yaml << EOF
kind: Pod
apiVersion: v1
metadata:
  name: test-nfs-pod1
spec:
  containers:
  - name: test-pod
    image: busybox:latest
    command: [ "sleep", "3600" ]
    volumeMounts:
      - name: nfs-pvc
        mountPath: "/mnt"
  restartPolicy: "Never"
  volumes:
    - name: nfs-pvc
      persistentVolumeClaim:
        claimName: test-claim
EOF
kubectl apply -f test-pvc.yaml

kubectl apply -f test-nfs-pod1.yaml
kubectl get pods -o wide 
kubectl describe pod test-nfs-pod1
kubectl exec -it test-nfs-pod1   /bin/sh

cd /mnt/
写入8M大小文件
time dd if=/dev/zero of=./test_w bs=8k count=100000

ll /nfs/k8s/dpv/default-test-claim-pvc-505ec1a4-4b79-4fb4-a1b6-4a26bccdd65a
-rw-r--r--. 1 root root 7.9M Oct 20 13:36 test_w

当初pvc 是申请了2M,storage: 2Mi,当前写入8M, 可见pvc是无法限制空间大小的,使用的还是nfs的共享大小。

kubectl delete -f test-nfs-pod1.yaml
kubectl delete -f test-pvc.yaml

创建一个nginx测试

准备镜像
docker pull docker.io/library/nginx:1.21.4
docker tag docker.io/library/nginx:1.21.4 repo.k8s.local/library/nginx:1.21.4
docker push repo.k8s.local/library/nginx:1.21.4
nginx yaml文件
cat > test-nginx.yaml <<EOF
apiVersion: v1
kind: Service
metadata:
  labels: {app: nginx}
  name: test-nginx
  namespace: test
spec:
  ports:
  - {name: t9080, nodePort: 30002, port: 30080, protocol: TCP, targetPort: 80}
  selector: {app: nginx}
  type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy
  namespace: test
  labels: {app: nginx}
spec:
  replicas: 1
  selector:
    matchLabels: {app: nginx}
  template:
    metadata:
      name: nginx
      labels: {name: nginx}
    spec:
      containers:
      - name: nginx
        #image: docker.io/library/nginx:1.21.4
        image: repo.k8s.local/library/nginx:1.21.4
        volumeMounts:
        - name: volv
          mountPath: /data
      volumes:
      - name: volv
        persistentVolumeClaim:
          claimName: test-pvc2
      nodeSelector:
        ingresstype: ingress-nginx
EOF

准备pvc

注意namesapce要和 service一致

cat > test-pvc2.yaml  << EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc2
  namespace: test
spec:
  storageClassName: managed-nfs-storage  
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 300Mi
EOF
创建命名空间并执行
kubectl create ns test
kubectl apply -f  test-pvc2.yaml
kubectl apply -f  test-nginx.yaml
kubectl get -f test-nginx.yaml

#修改动态pv加收为Retain
kubectl edit pv -n default pvc-f9153444-5653-4684-a845-83bb313194d1
persistentVolumeReclaimPolicy: Retain

kubectl get pods -o wide -n test                   
NAME                     READY   STATUS    RESTARTS   AGE    IP       NODE     NOMINATED NODE   READINESS GATES
nginx-5ccbddff9d-k2lgs   0/1     Pending   0          8m6s   <none>   <none>   <none>           <none>

kubectl -n test describe pod nginx-5ccbddff9d-k2lgs 
 Warning  FailedScheduling  53s (x2 over 6m11s)  default-scheduler  0/3 nodes are available: persistentvolumeclaim "test-claim" not found. preemption: 0/3 nodes are available: 3 Preemption is not helpful for scheduling..

get pv -o wide -n test 
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS          REASON   AGE   VOLUMEMODE
pvc-16c63bbf-11c4-49aa-8289-7e4c64c78c2b   2Mi        RWX            Delete           Bound    default/test-claim   managed-nfs-storage            84m   Filesystem
NAME                     READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
nginx-5bc65c5745-rsp6s   0/1     Pending   0          17h   <none>   <none>   <none>           <none>

kubectl -n test describe pod/nginx-5bc65c5745-rsp6s 
Warning  FailedScheduling  4m54s (x206 over 17h)  default-scheduler  0/3 nodes are available: persistentvolumeclaim "test-pvc2" not found. preemption: 0/3 nodes are available: 3 Preemption is not helpful for scheduling..
#注意检查pvc的namespace和service是否一致

当前pvc是Delete 状态,还没回收  
kubectl delete -f test-pvc2.yaml  
kubectl delete -f test-nginx.yaml  

kubectl get pv,pvc -o wide  
kubectl get pvc -o wide  
kubectl get pods -o wide -n test
#进入容器,修改内容
kubectl exec -it nginx-5c5c944c4f-4v5g7  -n test -- /bin/sh
cat /etc/nginx/conf.d/default.conf

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

  access_log  /var/log/nginx/access.log  main;
echo `hostname` >> /usr/share/nginx/html/index.html
Ingress资源

namespace 要一致

cat > ingress_svc_test.yaml  << EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-svc-test
  annotations:
    kubernetes.io/ingress.class: "nginx"
  namespace: test
spec:
  rules:
  - http:
      paths:
      - path: /testpath
        pathType: Prefix
        backend:
          service:
            name: test-nginx
            port:
              number: 30080
EOF
cat > ingress_svc_test.yaml  << EOF
apiVersion: extensions/v1
kind: Ingress
metadata:
  name: my-ingress
  namespace: test
spec:
  backend:
    serviceName: test-nginx
    servicePort: 30080
EOF

kubectl apply -f ingress_svc_test.yaml
kubectl describe ingress ingress-svc-test -n test

cat > ingress_svc_dashboard.yaml  << EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: dashboard
  namespace: kube-system
spec:
  rules:
  - http:
      paths:
      - path: /dashboard
        pathType: Prefix
        backend:
          service:
            name: kubernetes-dashboard
            port:
              number: 443
EOF

查看系统service资源

kubectl get service –all-namespaces

备份pv数据

首先根据pvc找到对应的pv:

kubectl get pv,pvc
kubectl -n default get pvc nfs-pvc001 -o jsonpath='{.spec.volumeName}'
nfs-spv001

找到pv的挂载目录:

kubectl -n default get pv nfs-spv001
kubectl -n default describe pv nfs-spv001
Source:
    Type:      NFS (an NFS mount that lasts the lifetime of a pod)
    Server:    192.168.0.244.6
    Path:      /nfs/k8s/spv_001

使用rsync命令备份数据:

rsync -avp --delete /nfs/k8s/spv_001 /databak/pvc-data-bak/default/spv_001/

还原

rsync -avp --delete /databak/pvc-data-bak/default/spv_001/ /nfs/k8s/spv_001/

批量回收pv

kubectl get pv 
当pv标记为Recycle时,删除pvc,pv STATUS 为Released/Failed ,删除claimRef段后恢复 Available
kubectl edit pv pvc-6f57e98a-dcc8-4d65-89c6-49826b2a3f18
kubectl patch pv pvc-91e17178-5e99-4ef1-90c2-1c9c2ce33af9 --patch '{"spec": {"claimRef":null}}'

kubectl delete pv pvc-e99c588a-8834-45b2-a1a9-85e31dc211ff
1.导出废弃pv在nfs服务器上的对应路径
kubectl get pv \
    -o custom-columns=STATUS:.status.phase,PATH:.spec.nfs.path \
    |grep Released  \
    |awk '{print $2}' \
> nfsdir.txt
2 清理k8s中的废弃pv

vi k8s_cleanpv.sh

#!/bin/bash
whiteList=`kubectl get pv |grep  Released |awk '{print $1}'`
echo "${whiteList}" | while read line
do
  kubectl patch pv ${line}  -p '{"spec":{"persistentVolumeReclaimPolicy":"Delete"}}'
done
3 清理nfs服务器上的废弃文件

vi ./k8s_pv_cleaner.sh

#!/bin/bash
whiteList=`cat $1`
echo "${whiteList}" | while read line
do
  rm -rf  "$line"
done

./k8s_pv_cleaner.sh nfsdir.txt

错误

no matches for kind "Ingress" in version "networking.k8s.io/v1beta
1.19版本以后,Ingress 所在的 apiServer 和配置文件参数都有所更改
apiVersion: networking.k8s.io/v1beta1 改为apiVersion: networking.k8s.io/v1

进入容器,创建数据

kubectl exec -it pod/test-nfs-pod -- sh
kubectl debug -it pod/test-nfs-pod --image=busybox:1.28 --target=pod_debug

kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh

删除测试的 Pod 资源文件

kubectl delete -f test-nfs-pod.yaml 

删除测试的 PVC 资源文件

kubectl delete -f test-pvc.yaml

错误
当nfs服务器重启后,原有挂nfs的pod不能关闭不能重启。
当nfs异常时,网元进程读nfs挂载目录超时卡住,导致线程占满,无法响应k8s心跳检测,一段时间后,k8s重启该网元pod,在终止pod时,由于nfs异常,umount卡住,导致pod一直处于Terminating状态。
为解决上述问题,需要实现如下两点:
1、若pod一直处于Terminating,也可以强制删除:kubectl delete pod foo –grace-period=0 –force
2、可使用mount -l | grep nfs,umount -l -f 执行强制umount操作
3、也可以先建立本地目录,让本地目录mount nfs设备,再将本地目录通过hostpath挂载到容器中,这样不管参数是否设置,pod均能删除,但是如果不设置参数,读取还会挂住

修改node默认挂载为Soft方式
vi /etc/nfsmount.conf

Soft=True

nfs对于高可用来说存在一个隐患:客户端nfs中有一个内核级别的线程,nfsv4.1-svc,该线程会一直和nfs服务端进行通信,且无法被kill掉。(停止客户端Nfs服务,设置开机不自启动,并卸载nfs,重启主机才能让该线程停掉)。一旦nfs服务端停掉,或者所在主机关机,那么nfs客户端就会找不到nfs服务端,导致nfs客户端所在主机一直处于卡死状态,表现为无法ssh到该主机,不能使用 df -h 等命令,会对客户造成比较严重的影响。

Posted in 安装k8s/kubernetes.

Tagged with , .


k8s_安装6_ipvs

安装六 ipvs

kube-proxy修改为ipvs模式
IPVS是Linux内核实现的四层负载均衡
kube-proxy三种模式中,现在使用的就是只有 iptables 模式 或者 ipvs 模式,不管哪种,这两个模式都是依赖 node 节点上的 iptables 规则
kube-proxy 的功能是将 svc 上的请求转发的 pod 上,无论是 iptables 模式还是 ipvs 模式,这个功能都是通过 iptables 链来完成的,iptables -t nat -L,可以打印出 kube-proxy 相关的链

查看当前模式

通过 kubectl 命令查看 kube-proxy 的配置

kubectl get configmap kube-proxy -n kube-system -o yaml | grep mode
    mode: ""
#空表示iptables

#查看日志
kubectl get pods -n kube-system -o wide| grep proxy
kube-proxy-58mfp                             1/1     Running   0             6d3h   192.168.244.5   node01.k8s.local     <none>           <none>
kube-proxy-z9tpc                             1/1     Running   0             6d3h   192.168.244.4   master01.k8s.local   <none>           <none>

kubectl logs kube-proxy-z9tpc -n kube-system 
1011 03:20:57.180789       1 server_others.go:69] "Using iptables proxy"

#查看端口
netstat -lntp 
tcp        0      0 127.0.0.1:10257         0.0.0.0:*               LISTEN      8204/kube-controlle 
tcp        0      0 127.0.0.1:10249         0.0.0.0:*               LISTEN      22903/kube-proxy 

将kube_proxy 切换为ipvs

kube-proxy默认监听的地址是127.0.0.1:10249,想要修改监听的端口
把metricsBindAddress这段修改成 metricsBindAddress: "0.0.0.0:10249"
ipvs修改mode: "ipvs"

#在master节点,修改编辑kube-proxy 这个configmap文件,修改模式为ipvs,同时改监听ip为全部:
    metricsBindAddress: ""
    mode: ""

kubectl edit configmaps kube-proxy -n kube-system

    kind: KubeProxyConfiguration
    logging:
      flushFrequency: 0
      options:
        json:
          infoBufferSize: "0"
      verbosity: 0
    metricsBindAddress: "0.0.0.0:10249"
    mode: "ipvs"
    nodePortAddresses: null
    oomScoreAdj: null
    portRange: ""

重启kube-proxy

# 我们发现修改kube-proxy 这个configmap文件后,查看pod的日志,发现ipvs模式并没有立即生效,所以我们需要删除kube-proxy的pod,这些pod是
# 由DaemonSet控制,删除之后DaemonSet会重新在每个节点创建的

#kubectl get pods -n kube-system | grep kube-proxy |awk '{print $1}' | xargs kubectl delete pods -n kube-system
kubectl  delete pods -n kube-system -l k8s-app=kube-proxy
pod "kube-proxy-58mfp" deleted
pod "kube-proxy-z9tpc" deleted

kubectl get pods -n kube-system -o wide| grep proxy       
kube-proxy-pgr2j                             1/1     Running   0             3s     192.168.244.4   master01.k8s.local   <none>           <none>
kube-proxy-xgmqz                             1/1     Running   0             3s     192.168.244.5   node01.k8s.local     <none>           <none>
kubectl logs kube-proxy-pgr2j -n kube-system 
I1017 07:21:40.118590       1 server_others.go:218] "Using ipvs Proxier"
I1017 07:21:40.118809       1 server_others.go:421] "Detect-local-mode set to ClusterCIDR, but no cluster CIDR for family" ipFamily="IPv6"

kubectl logs kube-proxy-xgmqz -n kube-system 
I1017 07:21:39.951567       1 server_others.go:218] "Using ipvs Proxier"
I1017 07:21:39.951590       1 server_others.go:421] "Detect-local-mode set to ClusterCIDR, but no cluster CIDR for family" ipFamily="IPv6"

#curl请求内部确认
curl 127.0.0.1:10249/proxyMode
ipvs

#查看端口
ss  -antulp |grep :10249
tcp    LISTEN     0      4096   [::]:10249              [::]:*                   users:(("kube-proxy",pid=5764,fd=10))

外部访问测试

http://192.168.244.4:10249/proxyMode
ipvs

查看当前ipvs转发规则

ipvsadm

IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  node02.k8s.local:30080 rr
  -> node01.k8s.local:http        Masq    1      0          0         
  -> node02.k8s.local:http        Masq    1      0          0         
TCP  node02.k8s.local:30443 rr
  -> node01.k8s.local:https       Masq    1      0          0         
  -> node02.k8s.local:https       Masq    1      0          0         
TCP  node02.k8s.local:30801 rr
  -> 10.244.2.9:irdmi             Masq    1      0          0         
TCP  node02.k8s.local:32080 rr
  -> 10.244.2.24:8089             Masq    1      0          0         
TCP  node02.k8s.local:https rr
  -> master01.k8s.local:sun-sr-ht Masq    1      4          0         
TCP  node02.k8s.local:domain rr
  -> 10.244.0.10:domain           Masq    1      0          0         
  -> 10.244.0.11:domain           Masq    1      0          0         
TCP  node02.k8s.local:9153 rr
  -> 10.244.0.10:9153             Masq    1      0          0         
  -> 10.244.0.11:9153             Masq    1      0          0         
TCP  node02.k8s.local:irdmi rr
  -> 10.244.2.9:irdmi             Masq    1      0          0         
TCP  node02.k8s.local:31080 rr
  -> 10.244.2.24:8089             Masq    1      0          0         
TCP  node02.k8s.local:cslistener rr
  -> 10.244.2.8:cslistener        Masq    1      0          0         
TCP  node02.k8s.local:http rr
  -> node01.k8s.local:http        Masq    1      0          0         
  -> node02.k8s.local:http        Masq    1      0          0         
TCP  node02.k8s.local:https rr
  -> node01.k8s.local:https       Masq    1      0          0         
  -> node02.k8s.local:https       Masq    1      0          0         
TCP  node02.k8s.local:https rr
  -> node01.k8s.local:pcsync-http Masq    1      0          0         
  -> node02.k8s.local:pcsync-http Masq    1      0          0         
TCP  node02.k8s.local:irdmi rr
  -> 10.244.2.10:irdmi            Masq    1      0          0         
TCP  node02.k8s.local:31080 rr
  -> 10.244.1.93:http             Masq    1      0          0         
TCP  node02.k8s.local:30080 rr
  -> node01.k8s.local:http        Masq    1      0          0         
  -> node02.k8s.local:http        Masq    1      0          0         
TCP  node02.k8s.local:30443 rr
  -> node01.k8s.local:https       Masq    1      0          0         
  -> node02.k8s.local:https       Masq    1      0          0         
TCP  node02.k8s.local:30801 rr
  -> 10.244.2.9:irdmi             Masq    1      0          0         
TCP  node02.k8s.local:32080 rr
  -> 10.244.2.24:8089             Masq    1      0          0         
TCP  node02.k8s.local:30080 rr
  -> node01.k8s.local:http        Masq    1      0          0         
  -> node02.k8s.local:http        Masq    1      0          0         
TCP  node02.k8s.local:30443 rr
  -> node01.k8s.local:https       Masq    1      0          0         
  -> node02.k8s.local:https       Masq    1      0          0         
TCP  node02.k8s.local:30801 rr
  -> 10.244.2.9:irdmi             Masq    1      0          0         
TCP  node02.k8s.local:32080 rr
  -> 10.244.2.24:8089             Masq    1      0          0         
UDP  node02.k8s.local:domain rr
  -> 10.244.0.10:domain           Masq    1      0          0         
  -> 10.244.0.11:domain           Masq    1      0          0  

IPVS支持三种负载均衡模式

Direct Routing(简称DR),Tunneling(也称ipip模式)和NAT(也称Masq模式)

DR

IPVS的DR模式是最广泛的IPVS模式,它工作在L2,即通过Mac地址做LB,而非IP地址。在DR模式下,回程报文不会经过IPVS director 而是直接返回给客户端。因此,DR在带来高性能的同时,对网络也有一定的限制,及要求IPVS的director 和客户端在同一个局域网。另外,比较遗憾的是,DR不支持端口映射,无法支持kubernetes service的所有场景。

TUNNELING

IPVS的Tunneling模式就是用IP包封装IP包,因此也称ipip模式。Tunneling模式下的报文不经过IPVS director,而是直接回复给客户端。Tunneling模式统一不支持端口映射,因此很难被用在kubernetes的service场景中。

NAT

IPVS的NAT模式支持端口映射,回程报文需要经过IPVS director,因此也称Masq(伪装)模式。 kubernetes在用IPVS实现Service时用的正式NAT模式。 当使用NAT模式时,需要注意对报文进行一次SNAT,这也是kubernetes使用IPVS实现Service的微妙之处。

IPVS的八种调度算法

rr|wrr|lc|wlc|lblc|lblcr|dh|sh|sed|nq

  1. 轮叫调度 rr
    这种算法是最简单的,就是按依次循环的方式将请求调度到不同的服务器上,该算法最大的特点就是简单。轮询算法假设所有的服务器处理请求的能力都是一样的,调度器会将所有的请求平均分配给每个真实服务器,不管后端 RS 配置和处理能力,非常均衡地分发下去。

  2. 加权轮叫 wrr
    这种算法比 rr 的算法多了一个权重的概念,可以给 RS 设置权重,权重越高,那么分发的请求数越多,权重的取值范围 0 – 100。主要是对rr算法的一种优化和补充, LVS 会考虑每台服务器的性能,并给每台服务器添加要给权值,如果服务器A的权值为1,服务器B的权值为2,则调度到服务器B的请求会是服务器A的2倍。权值越高的服务器,处理的请求越多。

  3. 最少链接 lc
    这个算法会根据后端 RS 的连接数来决定把请求分发给谁,比如 RS1 连接数比 RS2 连接数少,那么请求就优先发给 RS1

  4. 加权最少链接 wlc
    这个算法比 lc 多了一个权重的概念。

  5. 基于局部性的最少连接调度算法 lblc
    这个算法是请求数据包的目标 IP 地址的一种调度算法,该算法先根据请求的目标 IP 地址寻找最近的该目标 IP 地址所有使用的服务器,如果这台服务器依然可用,并且有能力处理该请求,调度器会尽量选择相同的服务器,否则会继续选择其它可行的服务器

  6. 复杂的基于局部性最少的连接算法 lblcr
    记录的不是要给目标 IP 与一台服务器之间的连接记录,它会维护一个目标 IP 到一组服务器之间的映射关系,防止单点服务器负载过高。

  7. 目标地址散列调度算法 dh
    该算法是根据目标 IP 地址通过散列函数将目标 IP 与服务器建立映射关系,出现服务器不可用或负载过高的情况下,发往该目标 IP 的请求会固定发给该服务器。

  8. 源地址散列调度算法 sh
    与目标地址散列调度算法类似,但它是根据源地址散列算法进行静态分配固定的服务器资源。

kube-proxy IPVS参数

在运行基于IPVS的kube-proxy时,需要注意以下参数:

  • -proxy-mode:除了现有的userspace和iptables模式,IPVS模式通过–proxymode=ipvs进行配置。
  • -ipvs-scheduler:用来指定ipvs负载均衡算法,如果不配置则默认使用round-robin(rr)算法。
  • -cleanup-ipvs:类似于–cleanup-iptables参数。如果设置为true,则清除在IPVS模式下创建的IPVS规则;
  • -ipvs-sync-period:表示kube-proxy刷新IPVS规则的最大间隔时间,例如5秒。1分钟等,要求大于0;
  • -ipvs-min-sync-period:表示kube-proxy刷新IPVS规则最小时间间隔,例如5秒,1分钟等,要求大于0
  • -ipvs-exclude-cidrs:用于清除IPVS规则时告知kube-proxy不要清理该参数配置的网段的IPVS规则。因为我们无法区别某条IPVS规则到底是kube-proxy创建的,还是其他用户进程的,配置该参数是为了避免删除用户自己的IPVS规则。

一旦创建一个Service和Endpoint,IPVS模式的kube-proxy会做以下三件事:

  • 1)确保一块dummy网卡(kube-ipvs0)存在,为什么要创建dummy网卡?因为IPVS的netfilter钩子挂载INPUT链,我们需要把Service的访问绑定在dummy网卡上让内核“觉得”虚IP就是本机IP,进而进入INPUT链。
  • 2)把Service的访问IP绑定在dummy网卡上
  • 3)通过socket调用,创建IPVS的virtual server和real server,分别对应kubernetes的Service和Endpoint。

PVS模式中的iptables和ipset
IPVS用于流量转发,它无法处理kube-proxy中的其他问题,例如包过滤、SNAT等。具体来说,IPVS模式的kube-proxy将在以下4中情况依赖iptables

kube-proxy 配置启动参数masquerade-all=true,即集群中所有经过Kube-proxy的包都将做一次SNAT
kube-proxy 启动参数指定集群IP地址范围
支持Load Balance 类型的服务,用于配置白名单
支持NodePort类型的服务,用于在包跨节点前配置MASQUERADE,类似于上文提到的iptables模式

Posted in 安装k8s/kubernetes.

Tagged with , , .


k8s_安装5_主体和CNI

五、k8s集群初始化

 安装 kubernetes 组件

所有节点均执行
由于kubernetes的镜像源在国外,速度比较慢,这里切换成国内的镜像源
创建/etc/yum.repos.d/kubernetes.repo文件并添加如下内容:

cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes] 
name=Kubernetes 
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 
enabled=1 
gpgcheck=0 
repo_gpgcheck=0 
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg 
       http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg 
EOF

wget -P /etc/yum.repos.d/ http://mirrors.aliyun.com/repo/epel-archive-6.repo

安装kubeadm、kubelet和kubectl

此处指定版本为 kubectl-1.28.2,如果不指定默认下载最新版本。

yum install --setopt=obsoletes=0 kubelet-1.28.2  kubeadm-1.28.2  kubectl-1.28.2 

配置kubelet的cgroup

# 编辑/etc/sysconfig/kubelet,添加下面的配置 
cat > /etc/sysconfig/kubelet << EOF
KUBELET_CGROUP_ARGS="--cgroup-driver=systemd" 
KUBE_PROXY_MODE="ipvs" 
EOF

设置kubelet开机自启

systemctl enable kubelet
kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"28", GitVersion:"v1.28.2", GitCommit:"89a4ea3e1e4ddd7f7572286090359983e0387b2f", GitTreeState:"clean", BuildDate:"2023-09-13T09:34:32Z", GoVersion:"go1.20.8", Compiler:"gc", Platform:"linux/amd64"}

准备集群镜像

以下步骤是在 master 节点进行,如果你可以访问到 http://k8s.gcr.io ,那么就可以直接跳过该步骤。

这种方法是先下载镜像,由于默认拉取镜像地址k8s.gcr.io国内无法访问,
所以在安装kubernetes集群之前,提前准备好集群需要的镜像,所需镜像可以通过下面命令查看

# 要下载镜像版本列表
kubeadm config images list
registry.k8s.io/kube-apiserver:v1.28.2
registry.k8s.io/kube-controller-manager:v1.28.2
registry.k8s.io/kube-scheduler:v1.28.2
registry.k8s.io/kube-proxy:v1.28.2
registry.k8s.io/pause:3.9
registry.k8s.io/etcd:3.5.9-0
registry.k8s.io/coredns/coredns:v1.10.1

方式一

推荐在harbor仓库机进行镜像操作,操作docker比contained更方便
节省带宽、时间、空间、不暴露密码、命令更简单。

docker images

docker添加私仓地址

vi /etc/docker/daemon.json
"registry-mirrors":["http://hub-mirror.c.163.com"],
"insecure-registries":["repo.k8s.local:5100"],

重启docker

systemctl daemon-reload
systemctl restart docker
docker info
Client: Docker Engine - Community
 Version:    24.0.6

登录harbor

使用harbor中新建的开发或维护用户登录

docker login  http://repo.k8s.local:5100               
Username: k8s_user1
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

登录成功后,下次就不需再登录

测试

手动推送私仓
docker pull registry.aliyuncs.com/google_containers/kube-apiserver:v1.28.2 
docker tag registry.aliyuncs.com/google_containers/kube-apiserver:v1.28.2  repo.k8s.local:5100/google_containers/kube-apiserver:v1.28.2 
docker push repo.k8s.local:5100/google_containers/kube-apiserver:v1.28.2

docker pull busybox
docker tag busybox repo.k8s.local:5100/google_containers/busybox:9.9
docker images |tail -1
docker push repo.k8s.local:5100/google_containers/busybox:9.9

去Harbor查看是否有对应的镜像,如果有表示成功

在master上测试从私仓拉取

ctr -n k8s.io i pull -k --plain-http repo.k8s.local:5100/google_containers/busybox:9.9
ctr -n k8s.io images ls  |grep busybox
repo.k8s.local:5100/google_containers/busybox:9.9                                                                                       application/vnd.docker.distribution.manifest.v2+json      sha256:023917ec6a886d0e8e15f28fb543515a5fcd8d938edb091e8147db4efed388ee 2.1 MiB   linux/amd64 
批量打标

不想改布署yml文件

# 下载镜像,重新标记为官方TAG,删除被标记的阿里云的镜像
#!/bin/bash
images=$(kubeadm config images list --kubernetes-version=1.28.2 | awk -F'/' '{print $NF}')
for imageName in ${images[@]} ; do
    docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName 
    docker tag registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName registry.k8s.io/$imageName
    docker rmi registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName
done
批量打标并推送私仓

repo.k8s.local:5100下已准备好 google_containers 仓库名
如在harbor仓库安装,可以在master导出文本到本地images.txt中,本地脚本中注释kubeadm 行,直接读images.txt

#下载镜像,重新标记为私有仓库,并推送到私有仓库,删除被标记的阿里云的镜像
vi docker_images.sh
#!/bin/bash
imagesfile=images.txt
$(kubeadm config images list --kubernetes-version=1.28.2 | awk -F'/' '{print $NF}' > ${imagesfile})
images=$(cat ${imagesfile})
for i in ${images}
do
echo ${i}
docker pull registry.aliyuncs.com/google_containers/$i
docker tag registry.aliyuncs.com/google_containers/$i repo.k8s.local:5100/google_containers/$i
docker push repo.k8s.local:5100/google_containers/$i
docker rmi registry.aliyuncs.com/google_containers/$i
done
chmod +x docker_images.sh
sh docker_images.sh

kubeadm config images list –kubernetes-version=1.28.2 | awk -F’/’ ‘{print $NF}’ > images.txt

查看下载的镜像
docker images

方式二

在master和node上用containers操作
containers镜像导入命令和docker有所不同,推私仓拉取时需带–all-platforms,此时会占用大量空间和带宽。

# 导入好镜像以后用crictl查看ctr也能查看,但是不直观
crictl images
ctr -n k8s.io images ls  
ctr -n k8s.io image import 加镜像名字 # 或者导入自己的镜像仓库在pull下来

#测试打标成官方,
ctr -n k8s.io i pull -k registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.28.2
ctr -n k8s.io i tag  registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.28.2 registry.k8s.io/kube-apiserver:v1.28.2
ctr -n k8s.io i rm registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.28.2 

测试推送私仓,拉取时需加--all-platforms
ctr -n k8s.io i pull -k --all-platforms registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.28.2
ctr -n k8s.io i tag  registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.28.2 repo.k8s.local:5100/google_containers/kube-apiserver:v1.28.2
ctr -n k8s.io i push -k --user k8s_user1:k8s_Uus1 --plain-http repo.k8s.local:5100/google_containers/kube-apiserver:v1.28.2

错误1

ctr: content digest sha256:07742a71be5e2ac5dc434618fa720ba38bebb463e3bdc0c58b600b4f7716bc3d: not found

拉取镜像、导出镜像时,都加上–all-platforms

错误2

ctr: failed to do request: Head "https://repo.k8s.local:5100/v2/google_containers/kube-apiserver/blobs/sha256:2248d40e3af29ab47f33357e4ecdc9dca9a89daea07ac3a5a76de583ed06c776": http: server gave HTTP response to HTTPS client

如harbor没开https,推送时加上 -user ${harboruser}:${harborpwd} –plain-http

#下载镜像,重新标记为私有仓库,并推送到私有仓库,删除被标记的阿里云的镜像
vi ctr_images.sh
#!/bin/bash
harboruser=k8s_user1
harborpwd=k8s_Uus1
images=$(kubeadm config images list --kubernetes-version=1.28.2 | awk -F'/' '{print $NF}')
for imageName in ${images[@]} ; do
    ctr -n k8s.io i pull -k -all-platforms registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName 
    #ctr -n k8s.io i tag registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName registry.k8s.io/$imageName
    ctr -n k8s.io i tag registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName repo.k8s.local:5100/google_containers/$imageName
    ctr -n k8s.io i push --user ${harboruser}:${harborpwd} --plain-http repo.k8s.local:5100/google_containers/$imageName
    #ctr -n k8s.io i rm registry.cn-hangzhou.aliyuncs.com/google_containers/$imageName
done
chmod +x ctr_images.sh
./ctr_images.sh
crictl images
FATA[0000] validate service connection: CRI v1 image API is not implemented for endpoint "unix:///var/run/containerd/containerd.sock": rpc error: code = Unimplemented desc = unknown service runtime.v1.ImageService 

修复错误

#找到runtime_type 写入"io.containerd.runtime.v1.linux"

vi /etc/containerd/config.toml
      [plugins."io.containerd.grpc.v1.cri".containerd.default_runtime]
        base_runtime_spec = ""
        cni_conf_dir = ""
        cni_max_conf_num = 0
        container_annotations = []
        pod_annotations = []
        privileged_without_host_devices = false
        privileged_without_host_devices_all_devices_allowed = false
        runtime_engine = ""
        runtime_path = ""
        runtime_root = ""
        runtime_type = "io.containerd.runtime.v1.linux"
        sandbox_mode = ""
        snapshotter = ""
systemctl restart containerd
crictl images               
IMAGE               TAG                 IMAGE ID            SIZE

还有种方法是关闭cri插件,还没试过

cat /etc/containerd/config.toml |grep cri
sed -i -r '/cri/s/(.*)/#\1/' /etc/containerd/config.toml

创建集群

目前生产部署Kubernetes集群主要有两种方式:

    1. kubeadm安装
      Kubeadm 是一个 K8s 部署工具,提供 kubeadm init 和 kubeadm join,用于快速部 署 Kubernetes 集群。
      官方地址:https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm/
    1. 二进制包安装
      从 github 下载发行版的二进制包,手动部署每个组件,组成 Kubernetes 集群。
      Kubeadm 降低部署门槛,但屏蔽了很多细节,遇到问题很难排查。如果想更容易可 控,推荐使用二进制包部署 Kubernetes 集群,虽然手动部署麻烦点,期间可以学习很 多工作原理,也利于后期维护。

kubeadm 安装

初始化集群

下面的操作只需要在master节点上执行即可

systemctl start kubelet && systemctl enable kubelet && systemctl is-active kubelet
kubeadm config print init-defaults | tee kubernetes-init.yaml

kubeadm 创建集群

参考: https://kubernetes.io/zh-cn/docs/reference/setup-tools/kubeadm/kubeadm-init/

A. 命令行:
kubeadm init \
--kubernetes-version=v1.28.2 \
--image-repository registry.aliyuncs.com/google_containers \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.96.0.0/16 \
--apiserver-advertise-address=192.168.244.4 \
--cri-socket unix:///var/run/containerd/containerd.sock
kubeadm init 选项说明

为控制平面选择一个特定的 Kubernetes 版本。
–kubernetes-version string 默认值:"stable-1"
选择用于拉取控制平面镜像的容器仓库。
–image-repository string 默认值:"registry.k8s.io"
指明 Pod 网络可以使用的 IP 地址段。如果设置了这个参数,控制平面将会为每一个节点自动分配 CIDR。
–pod-network-cidr string
为服务的虚拟 IP 地址另外指定 IP 地址段。
–service-cidr string 默认值:"10.96.0.0/12"
API 服务器所公布的其正在监听的 IP 地址。如果未设置,则使用默认网络接口。
–apiserver-advertise-address string
要连接的 CRI 套接字的路径。如果为空,则 kubeadm 将尝试自动检测此值; 仅当安装了多个 CRI 或具有非标准 CRI 套接字时,才使用此选项。
–cri-socket string

不做任何更改;只输出将要执行的操作。
–dry-run
指定节点的名称。
–node-name string
为服务另外指定域名,例如:"myorg.internal"。
–service-dns-domain string 默认值:"cluster.local"

B. 配置文件

命令行方式指定参数执行起来非常冗余,尤其参数比较多的情况,此时可以将所有的配置要求写到配置文件中,部署的时候指定对应的配置文件即可,假设取名kubernetes-init.yaml:
写好配置文件后,直接执行:

vi kubernetes-init.yaml

apiVersion: kubeadm.k8s.io/v1beta3
bootstrapTokens:
- groups:
  - system:bootstrappers:kubeadm:default-node-token
  token: abcdef.0123456789abcdef
  ttl: 24h0m0s
  usages:
  - signing
  - authentication
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: 192.168.244.4
  bindPort: 6443
nodeRegistration:
  criSocket: unix:///var/run/containerd/containerd.sock
  imagePullPolicy: IfNotPresent
  name: node
  taints: null
---
apiServer:
  timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta3
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
controllerManager: {}
dns: {}
etcd:
  local:
    dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers
kind: ClusterConfiguration
kubernetesVersion: 1.28.2
networking:
  dnsDomain: cluster.local
  serviceSubnet: 10.96.0.0/16
scheduler: {}

kubeadm init –config kubeadm.yaml

查看启动service

cat /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf
# Note: This dropin only works with kubeadm and kubelet v1.11+
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
# This is a file that "kubeadm init" and "kubeadm join" generates at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically
EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
# This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use
# the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file.
EnvironmentFile=-/etc/sysconfig/kubelet
ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS

防雪崩,同时限制pod、k8s系统组件、linux系统守护进程资源

https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/node-pressure-eviction/
当工作节点的磁盘,内存资源使用率达到阈值时会出发POD驱逐
工作节点修改/var/lib/kubelet/config.yaml 无效.需修改 /var/lib/kubelet/kubeadm-flags.env

默认的驱逐阈值如下:
–eviction-hard default
imagefs.available<15%,memory.available<100Mi,nodefs.available<10%,nodefs.inodesFress<5%

vi /var/lib/kubelet/config.yaml
只限pod,线上应增加memory.available值,留出kube和system和使用内存。
硬驱逐1G,软驱逐2G

enforceNodeAllocatable:
- pods
evictionHard:
  memory.available: "300Mi"
  nodefs.available: "10%"
  nodefs.inodesFree: "5%"
  imagefs.available: "10%"
evictionMinimumReclaim:
  memory.available: "0Mi"
  nodefs.available: "500Mi"
  imagefs.available: "2Gi"
evictionSoft:
  memory.available: "800Mi"
  nodefs.available: "15%"
  nodefs.inodesFree: "10%"
  imagefs.available: "15%"
evictionSoftGracePeriod:
  memory.available: "120s"
  nodefs.available: "120s"
  nodefs.inodesFree: "120s"
  imagefs.available: "120s"
evictionMaxPodGracePeriod: 30

systemctl restart kubelet
systemctl status kubelet

报错
grace period must be specified for the soft eviction threshold nodefs.available"
如果配制了软驱逐evictionSoft那么相应的evictionSoftGracePeriod也需配制

evictionSoft:
  nodefs.available: "15%"
  nodefs.inodesFree: "10%"
  imagefs.available: "15%"
  • enforceNodeAllocatable[]string
    此标志设置 kubelet 需要执行的各类节点可分配资源策略。此字段接受一组选项列表。 可接受的选项有 none、pods、system-reserved 和 kube-reserved。
    如果设置了 none,则字段值中不可以包含其他选项。
    如果列表中包含 system-reserved,则必须设置 systemReservedCgroup。
    如果列表中包含 kube-reserved,则必须设置 kubeReservedCgroup。
    这个字段只有在 cgroupsPerQOS被设置为 true 才被支持。
    默认值:["pods"]

  • evictionHardmap[string]string
    evictionHard 是一个映射,是从信号名称到定义硬性驱逐阈值的映射。 例如:{"memory.available": "300Mi"}。 如果希望显式地禁用,可以在任意资源上将其阈值设置为 0% 或 100%。
    默认值:
    memory.available: "100Mi"
    nodefs.available: "10%"
    nodefs.inodesFree: "5%"
    imagefs.available: "15%"

  • evictionSoftmap[string]string
    evictionSoft 是一个映射,是从信号名称到定义软性驱逐阈值的映射。 例如:{"memory.available": "300Mi"}。
    默认值:nil

  • evictionSoftGracePeriodmap[string]string
    evictionSoftGracePeriod 是一个映射,是从信号名称到每个软性驱逐信号的宽限期限。 例如:{"memory.available": "30s"}。
    默认值:nil

  • evictionPressureTransitionPeriod
    evictionPressureTransitionPeriod 设置 kubelet 离开驱逐压力状况之前必须要等待的时长。
    默认值:"5m"

  • evictionMaxPodGracePeriod int32
    evictionMaxPodGracePeriod 是指达到软性逐出阈值而引起 Pod 终止时, 可以赋予的宽限期限最大值(按秒计)。这个值本质上限制了软性逐出事件发生时, Pod 可以获得的 terminationGracePeriodSeconds。
    注意:由于 Issue #64530 的原因,系统中存在一个缺陷,即此处所设置的值会在软性逐出时覆盖 Pod 的宽限期设置,从而有可能增加 Pod 上原本设置的宽限期限时长。 这个缺陷会在未来版本中修复。
    默认值:0

  • evictionMinimumReclaimmap[string]string
    evictionMinimumReclaim 是一个映射,定义信号名称与最小回收量数值之间的关系。 最小回收量指的是资源压力较大而执行 Pod 驱逐操作时,kubelet 对给定资源的最小回收量。 例如:{"imagefs.available": "2Gi"}。
    默认值:nil

根据提示创建必要文件

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
export KUBECONFIG=/etc/kubernetes/admin.conf

此步骤执行完成之后,使用命令docker images查看系统中的镜像,可以我们需要的镜像均已安装完成。

记下输出,后面加入时使用

kubeadm join 192.168.244.4:6443 --token rynvll.2rdb5z78if3mtlgd \
        --discovery-token-ca-cert-hash sha256:42739a7aaff927af9dc3b77a5e684a93d1c6485a79b8d23c33d978476c6902e2 

删除或重新配置集群

kubeadm reset
rm -fr ~/.kube/  /etc/kubernetes/* var/lib/etcd/*

node节点也可以执行kubectl,如重置也一同删除

scp -r ~/.kube node01.k8s.local:~/
scp -r ~/.kube node02.k8s.local:~/

node节点加入集群

将 node 节点加入 master 中的集群(该命令在工作节点node中执行)。

yum install --setopt=obsoletes=0 kubelet-1.28.2  kubeadm-1.28.2  kubectl-1.28.2 

 Package                                                    Arch                                       Version                                           Repository                                      Size
==============================================================================================================================================================================================================
Installing:
 kubeadm                                                    x86_64                                     1.28.2-0                                          kubernetes                                      11 M
 kubectl                                                    x86_64                                     1.28.2-0                                          kubernetes                                      11 M
 kubelet                                                    x86_64                                     1.28.2-0                                          kubernetes                                      21 M
Installing for dependencies:
 conntrack-tools                                            x86_64                                     1.4.4-7.el7                                       base                                           187 k
 cri-tools                                                  x86_64                                     1.26.0-0                                          kubernetes                                     8.6 M
 kubernetes-cni                                             x86_64                                     1.2.0-0                                           kubernetes                                      17 M
 libnetfilter_cthelper                                      x86_64                                     1.0.0-11.el7                                      base                                            18 k
 libnetfilter_cttimeout                                     x86_64                                     1.0.0-7.el7                                       base                                            18 k
 libnetfilter_queue                                         x86_64                                     1.0.2-2.el7_2                                     base                                            23 k
 socat                                                      x86_64                                     1.7.3.2-2.el7                                     base                                           290 k

Transaction Summary
==============================================================================================================================================================================================================
systemctl enable --now kubelet
Created symlink from /etc/systemd/system/multi-user.target.wants/kubelet.service to /usr/lib/systemd/system/kubelet.service.

将node1节点加入集群

如果没有令牌,可以通过在控制平面节点上运行以下命令来获取令牌:

kubeadm token list
#默认情况下,令牌会在24小时后过期。如果要在当前令牌过期后将节点加入集群
#kubeadm token create
kubeadm token create --print-join-command

kubeadm join 192.168.244.4:6443 --token rynvll.2rdb5z78if3mtlgd \
        --discovery-token-ca-cert-hash sha256:42739a7aaff927af9dc3b77a5e684a93d1c6485a79b8d23c33d978476c6902e2 

[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

将node2节点加入集群

kubeadm join 192.168.244.4:6443 --token rynvll.2rdb5z78if3mtlgd \
        --discovery-token-ca-cert-hash sha256:42739a7aaff927af9dc3b77a5e684a93d1c6485a79b8d23c33d978476c6902e2 

查看集群状态 此时的集群状态为NotReady,这是因为还没有配置网络插件

kubectl get nodes
NAME                 STATUS     ROLES           AGE    VERSION
master01.k8s.local   NotReady   control-plane   5m2s   v1.28.2
node01.k8s.local     NotReady   <none>          37s    v1.28.2
kubectl get pods -A
NAMESPACE     NAME                                         READY   STATUS    RESTARTS   AGE
kube-system   coredns-66f779496c-9x9cf                     0/1     Pending   0          5m21s
kube-system   coredns-66f779496c-xwgtx                     0/1     Pending   0          5m21s
kube-system   etcd-master01.k8s.local                      1/1     Running   0          5m34s
kube-system   kube-apiserver-master01.k8s.local            1/1     Running   0          5m34s
kube-system   kube-controller-manager-master01.k8s.local   1/1     Running   0          5m34s
kube-system   kube-proxy-58mfp                             1/1     Running   0          72s
kube-system   kube-proxy-z9tpc                             1/1     Running   0          5m21s
kube-system   kube-scheduler-master01.k8s.local            1/1     Running   0          5m36s

删除子节点(在master主节点上操作)

# 假设这里删除 node3 子节点
kubectl drain node3 --delete-local-data --force --ignore-daemonsets
kubectl delete node node3

然后在删除的子节点上操作重置k8s(重置k8s会删除一些配置文件),这里在node3子节点上操作

kubeadm reset

然后在被删除的子节点上手动删除k8s配置文件、flannel网络配置文件 和 flannel网口:

rm -rf /etc/cni/net.d/
rm -rf /root/.kube/config
#删除cni网络
ifconfig cni0 down
ip link delete cni0
ifconfig flannel.1 down
ip link delete flannel.1

安装 Pod 网络插件

flannel/calico/cilium

如需将flannel网络切换calico网络
kubelet 配置必须增加 –network-plugin=cni 选项
kubec-proxy 组件不能采用 –masquerade-all 启动,因为会与 Calico policy 冲突,并且需要加上–proxy-mode=ipvs(ipvs模式),–masquerade-all=true(表示ipvs proxier将伪装访问服务群集IP的所有流量,)

安装flannel

# 最好提前下载镜像(所有节点)
wget -k https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

---
kind: Namespace
apiVersion: v1
metadata:
  name: kube-flannel
  labels:
    k8s-app: flannel
    pod-security.kubernetes.io/enforce: privileged
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  labels:
    k8s-app: flannel
  name: flannel
rules:
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - nodes/status
  verbs:
  - patch
- apiGroups:
  - networking.k8s.io
  resources:
  - clustercidrs
  verbs:
  - list
  - watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  labels:
    k8s-app: flannel
  name: flannel
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: flannel
subjects:
- kind: ServiceAccount
  name: flannel
  namespace: kube-flannel
---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    k8s-app: flannel
  name: flannel
  namespace: kube-flannel
---
kind: ConfigMap
apiVersion: v1
metadata:
  name: kube-flannel-cfg
  namespace: kube-flannel
  labels:
    tier: node
    k8s-app: flannel
    app: flannel
data:
  cni-conf.json: |
    {
      "name": "cbr0",
      "cniVersion": "0.3.1",
      "plugins": [
        {
          "type": "flannel",
          "delegate": {
            "hairpinMode": true,
            "isDefaultGateway": true
          }
        },
        {
          "type": "portmap",
          "capabilities": {
            "portMappings": true
          }
        }
      ]
    }
  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "vxlan"
      }
    }
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube-flannel-ds
  namespace: kube-flannel
  labels:
    tier: node
    app: flannel
    k8s-app: flannel
spec:
  selector:
    matchLabels:
      app: flannel
  template:
    metadata:
      labels:
        tier: node
        app: flannel
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/os
                operator: In
                values:
                - linux
      hostNetwork: true
      priorityClassName: system-node-critical
      tolerations:
      - operator: Exists
        effect: NoSchedule
      serviceAccountName: flannel
      initContainers:
      - name: install-cni-plugin
        image: docker.io/flannel/flannel-cni-plugin:v1.2.0
        command:
        - cp
        args:
        - -f
        - /flannel
        - /opt/cni/bin/flannel
        volumeMounts:
        - name: cni-plugin
          mountPath: /opt/cni/bin
      - name: install-cni
        image: docker.io/flannel/flannel:v0.22.3
        command:
        - cp
        args:
        - -f
        - /etc/kube-flannel/cni-conf.json
        - /etc/cni/net.d/10-flannel.conflist
        volumeMounts:
        - name: cni
          mountPath: /etc/cni/net.d
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      containers:
      - name: kube-flannel
        image: docker.io/flannel/flannel:v0.22.3
        command:
        - /opt/bin/flanneld
        args:
        - --ip-masq
        - --kube-subnet-mgr
        resources:
          requests:
            cpu: "100m"
            memory: "50Mi"
        securityContext:
          privileged: false
          capabilities:
            add: ["NET_ADMIN", "NET_RAW"]
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        - name: EVENT_QUEUE_DEPTH
          value: "5000"
        volumeMounts:
        - name: run
          mountPath: /run/flannel
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
        - name: xtables-lock
          mountPath: /run/xtables.lock
      volumes:
      - name: run
        hostPath:
          path: /run/flannel
      - name: cni-plugin
        hostPath:
          path: /opt/cni/bin
      - name: cni
        hostPath:
          path: /etc/cni/net.d
      - name: flannel-cfg
        configMap:
          name: kube-flannel-cfg
      - name: xtables-lock
        hostPath:
          path: /run/xtables.lock
          type: FileOrCreate

修改Network项的值,改为和–pod-network-cidr一样的值

vxlan/host-gw
host-gw 的性能损失大约在 10% 左右,而其他所有基于 VXLAN“隧道”机制的网络方案,性能损失都在 20%~30% 左右
Flannel host-gw 模式必须要求集群宿主机之间是二层连通的.就是node1和node2在一个局域网.通过arp协议可以访问到.

工作方式首选vxlan+DirectRouting

  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "vxlan",
        "Directrouting": true
      }
    }

准备镜像

由于有时国内网络的问题,需要修改image的地址,把所有的docker.io改为dockerproxy.com,或者下载下来后打标签

方式一。改地址

修改kube-flannel.yml中地址为能下载的

image: docker.io/flannel/flannel-cni-plugin:v1.2.0
image: docker.io/flannel/flannel:v0.22.3
方式二。下载到本地
docker pull docker.io/flannel/flannel-cni-plugin:v1.2.0
docker pull docker.io/flannel/flannel:v0.22.3

container 操作下载到本地

ctr -n k8s.io i pull -k docker.io/flannel/flannel-cni-plugin:v1.2.0
ctr -n k8s.io i pull -k docker.io/flannel/flannel:v0.22.3
方式三。下载后推送到本地私人仓库

批量打标签
如在harbor仓库安装,可以导出到images.txt中再执行

# cat docker_flannel.sh 
#!/bin/bash
imagesfile=images.txt
$(grep image kube-flannel.yml | grep -v '#' | awk -F '/' '{print $NF}' > ${imagesfile})
images=$(cat ${imagesfile})

for i in ${images}
do
docker pull flannel/$i
docker tag flannel/$i repo.k8s.local:5100/google_containers/$i
docker push repo.k8s.local:5100/google_containers/$i
docker rmi flannel/$i
done
#执行脚本文件:
sh docker_flannel.sh
查看镜像
crictl images 
IMAGE                                                                         TAG                 IMAGE ID            SIZE
docker.io/flannel/flannel-cni-plugin                                          v1.2.0              a55d1bad692b7       3.88MB
docker.io/flannel/flannel                                                     v0.22.3             e23f7ca36333c       27MB
应用安装
kubectl apply -f kube-flannel.yml

namespace/kube-flannel created
clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.apps/kube-flannel-ds created
查看pods
kubectl get pods -n kube-flannel
NAME                    READY   STATUS    RESTARTS   AGE
kube-flannel-ds-flgpn   1/1     Running   0          58s
kube-flannel-ds-qdw64   1/1     Running   0          58s
验证安装结果,仅在master节点执行,二进制tar.gz包安装所有节点都要操作
kubectl get pods -n kube-system
NAME                                         READY   STATUS    RESTARTS   AGE
coredns-66f779496c-9x9cf                     1/1     Running   0          118m
coredns-66f779496c-xwgtx                     1/1     Running   0          118m
etcd-master01.k8s.local                      1/1     Running   0          118m
kube-apiserver-master01.k8s.local            1/1     Running   0          118m
kube-controller-manager-master01.k8s.local   1/1     Running   0          118m
kube-proxy-58mfp                             1/1     Running   0          114m
kube-proxy-z9tpc                             1/1     Running   0          118m
kube-scheduler-master01.k8s.local            1/1     Running   0          118m

systemctl status containerd
systemctl status kubelet
systemctl restart kubelet
kubectl get nodes

run.go:74] "command failed" err="failed to run Kubelet: validate service connection: validate CRI v1 runtime API for endpoint \"unix:///var/run/containerd/containerd.sock\

检查containerd服务有无错误

failed to load plugin io.containerd.grpc.v1.cri" error="invalid plugin config: `mirrors` cannot be set when `config_path` is provided"

/etc/containerd/config.toml中config_path 和 registry.mirrors 取一配制

    [plugins."io.containerd.grpc.v1.cri".registry]
      #config_path = "/etc/containerd/certs.d"

      [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
         endpoint = ["https://registry.cn-hangzhou.aliyuncs.com"]
transport: Error while dialing dial unix /run/containerd/containerd.sock: connect: no such file or directory

/usr/lib/systemd/system/kubelet.service 里的Unit.After 改成 After=containerd.target如是docker改成After=docker.target
我这里修改之前的值是After=network-online.target

err="failed to run Kubelet: running with swap on is not supported, please disable swap

永久关闭swap

swapoff -a && sed -ri 's/.*swap.*/#&/' /etc/fstab
"Failed to run kubelet" err="failed to run Kubelet: misconfiguration: kubelet cgroup driver: \"systemd\" is different from docker cgroup driver: \"cgroupfs\""

经过分析后发现,是因为“kebernetes默认设置cgroup驱动为systemd,而docker服务的cgroup驱动为cgroupfs”,有两种决解决方式,方式一,将docker的服务配置文件修改为何kubernetes的相同,方式二是修改kebernetes的配置文件为cgroupfs,这里采用第一种。
修改docker服务的配置文件,“/etc/docker/daemon.json ”文件,添加如下
"exec-opts": ["native.cgroupdriver=systemd"]

node节点可执行kubectl

scp -r ~/.kube node02.k8s.local:~/

请忽略,安装自动补全后再设置

vi ~/.bashrc

source <(kubectl completion bash)
command -v kubecolor >/dev/null 2>&1 && alias k="kubecolor"
complete -o default -F __start_kubectl k
export PATH="/root/.krew/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin"

[ -f ~/.kube/aliases.sh ] && source ~/.kube/aliases.sh

source ~/.bashrc

Posted in 安装k8s/kubernetes.

Tagged with , , .


k8s_安装4_私仓harbor

四、harbor仓库

k8s经常使用的镜像地址

从 Kubernetes 1.25 开始,我们的容器镜像注册中心已经从 k8s.gcr.io 更改为 registry.k8s.io .
registry.aliyuncs.com/google_containers是定时同步kubernetes的镜像到阿里镜像仓库服务的,但只是K8S组件的镜像,阿里云镜像仓库有谷歌和RedHat的镜像,但是不全。
当我们下载k8s.gcr.io,gcr.io镜像和quay.io镜像,可以把k8s.gcr.io,gcr.io, quay.io镜像换成阿里云或其它国内镜像加速地址下,如下所示:

k8s中相关镜像

#k8s.io  不能访问
registry.k8s.io/kube-apiserver:v1.28.2
registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2

docker pull registry.aliyuncs.com/google_containers/kube-apiserver:v1.28.2
docker pull registry.k8s.io/dns/k8s-dns-node-cache:1.22.28
docker pull k8s.mirror.nju.edu.cn/dns/k8s-dns-node-cache:1.22.28

# gcr.io
gcr.io/k8s-staging-sig-storage/nfs-subdir-external-provisioner:v4.0.0
docker pull m.daocloud.io/gcr.io/k8s-staging-sig-storage/nfs-subdir-external-provisioner:v4.0.0
docker pull m.daocloud.io/gcr.io/k8s-staging-sig-storage/nfs-subdir-external-provisioner:v4.0.2

# k8s.gcr.io
k8s.gcr.io/pause:3.2
registry.aliyuncs.com/google_containers/pause:3.2

#docker.io
docker.io/flannel/flannel-cni-plugin:v1.2.0
https://registry.cn-hangzhou.aliyuncs.com

#quay.io 可以下载
quay.io/external_storage/nfs-client-provisioner:latest
docker pull quay.nju.edu.cn/jetstack/cert-manager-webhook:v1.13.1

#docker.elastic.co 可以下载,有时慢
docker.elastic.co/beats/filebeat:8.11.0

#没有登录,需先登录
Error response from daemon: pull access denied for registry.aliyuncs.com/google_containers/cert-manager-webhook, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
docker login registry.cn-hangzhou.aliyuncs.com
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/cert-manager-webhook:v1.13.2

私仓

Docker比较流行使用的三种私有仓库
Docker Registry,Nexus,Harbor

Docker Registry

通过使用 Docker Compose,我们可以轻松地在本地部署 Docker Registry.
Harbor完全是在Registry上的封装,目前比Registry功能主要的强化在于:

  • 提供UI界面
  • 提供基于角色管理的用户权限
  • 提供用户操作记录审计确认
  • 提供镜像
  • 提供对Helm Chart等的支持

Nexus

Java 开发中的那个 Maven 私服,对对对,就是这个 Nexus。Nexus它也可以应用于 docker 仓库。

优势

docker就可以安装,可以代理其它仓库并缓存到本地。
nexus3覆盖更全面,啥都可以做,是一个混合仓库maven、yum、npm的私服

repositories说明:(参考maven已有repositories介绍,因为刚开始进来maven相关的库是已经存在的)

  • maven-public:它的类型是group(分组)。即:仓库所有的访问读取入口,都是从 public 开始,读取会分别从 snapshots、releases、central 中都去找,只要其中一个找到就读取回来),就是本地仓库找不到,就去配置的网络仓库中去找【网络仓库地址,会在docker-public中配置阿里云加速镜像地址】
  • maven-releases 发布后的jar包,放到release中
  • maven-snapshots 测试的jar包,放到snapshots中
  • maven-central 它的类型是proxy(代理)。代理不存数据,是只读的。这个类似配置maven仓库时我们配置的一个aliyun仓库,帮我们去代理到aliyun仓库

nexus中有个默认自带的仓库列表,里面包含了各种各样的仓库。
这些仓库主要分为三类,代理仓库、宿主仓库和仓库组。

  • 代理仓库:代理仓库主要是让使用者通过代理仓库来间接访问外部的第三方远程仓库的。代理仓库会从被代理的仓库中下载构件,缓存在代理仓库中以供maven用户使用。

  • 宿主仓库: 宿主仓库主要是给我们自己用的,主要有2点作用:
        将私有的一些构件通过nexus中网页的方式上传到宿主仓库中给其他同事使用
        将自己开发好的一些构件发布到nexus的宿主仓库中以供其他同事使用。

  • 仓库组:(默认maven-public)仓库组中可以有多个代理仓库和宿主仓库,而maven用户只用访问一个仓库组就可以间接地访问这个组内所有的仓库,仓库组中多个仓库是有顺序的,当maven用户从仓库组下载构件时,仓库组会按顺序依次在组内的仓库中查找组件,查找到了立即返回给本地仓库,所以一般情况我们会将速度快的放在前面。仓库组内部实际上是没有构件内容的,他只是起到一个请求转发的作用,将maven用户下载构件的请求转发给组内的其他仓库处理。

Harbor 私仓

它是Docker Registry的更高级封装,它除了提供友好的Web UI界面,角色和用户权限管理,用户操作审计等功能外,它还整合了K8s的插件(Add-ons)仓库,即Helm通过chart方式下载,管理,安装K8s插件,而chartmuseum可以提供存储chart数据的仓库【注:helm就相当于k8s的yum】。另外它还整合了两个开源的安全组件,一个是Notary,另一个是Clair,Notary类似于私有CA中心,而Clair则是容器安全扫描工具,它通过各大厂商提供的CVE漏洞库来获取最新漏洞信息,并扫描用户上传的容器是否存在已知的漏洞信息,这两个安全功能对于企业级私有仓库来说是非常具有意义的。
harbor 的优势很明显,特别是可以自建文件夹进行分组这点就非常好。其实说实话,作为一个私有的镜像仓库,harbor 已经做得很好的了,唯一的缺点是它无法帮你下载镜像。
相比Nexus要费资源。使用 Harbor 必须要先安装 docker 以及 docker-compose。

安装参考:
https://agou-ops.cn/post/containerdharbor%E7%A7%81%E6%9C%89%E4%BB%93https/

Harbor相关地址

官网:​ ​https://goharbor.io/​​

Github地址:​ ​https://github.com/goharbor/harbor​​

操作文档:​ ​https://goharbor.io/docs/

Harbor安装有多种方式:

在线安装:从Docker Hub下载Harbor相关镜像,因此安装软件包非常小
离线安装:安装包包含部署的相关镜像,因此安装包比较大

只在仓库机器上执行
Harbor安装前提条件
Harbor被部署为几个Docker容器。因此,您可以在任何支持Docker的Linux发行版上部署它。目标主机需要安装Docker,并安装Docker Compose。
安装Harbor前,需要安装Docker engine,Docker Compose和Openssl。

私有库默认是不支持删除镜像的,需要修改config.yml配置文件,在storage节点下加入 delete: enabled: true
删tag不会回收空间

Harbor 高可用方式

http://t.csdnimg.cn/k43Ao

  1. 安装两台 Harbor 仓库,他们共同使用一个存储(一般常见的便是 NFS 共享存储)需要额外配置 Redis 和 PostgreSQL 以及 NFS 服务
  2. 安装两台 Harbor 仓库,并互相配置同步关系。

1.docker环境的安装

docker-ce安装

首先先把服务停止了,不要直接卸载

systemctl stop docker

重命名数据目录

把默认的docker目录改一下名称。

mv /var/lib/docker /var/lib/docker-bak

卸载旧版本

Docker 的旧版本被称为 docker 或 docker-engine。如果这些已安装,请卸载它们以及关联 的依赖关系。

yum remove docker docker-common docker-selinux docker-engine -y

安装docker-ce

## 阿里云源
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum -y install docker-ce

docker version
Client: Docker Engine – Community
Version: 26.1.0
API version: 1.45
Go version: go1.21.9
Git commit: 9714adc
Built: Mon Apr 22 17:09:57 2024
OS/Arch: linux/amd64
Context: default
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors":["https://docker.nju.edu.cn/"],
"insecure-registries":["repo.k8s.local"],
"exec-opts":["native.cgroupdriver=systemd"],
"data-root": "/var/lib/docker",
"max-concurrent-downloads": 10,
"max-concurrent-uploads": 5,
"log-driver":"json-file",
"log-opts": {
"max-size": "300m",
"max-file": "2"
},
"experimental": true,
"live-restore": true
}
EOF

报错
Failed to chown socket at step GROUP: No such process
可能是文件被锁定,用户组没添加成功

lsattr /etc/passwd /etc/shadow /etc/group /etc/gshadow /etc/services
----i----------- /etc/passwd
----i----------- /etc/shadow
----i----------- /etc/group
----i----------- /etc/gshadow
----i----------- /etc/services
chattr -i /etc/passwd /etc/shadow /etc/group /etc/gshadow /etc/services
groupadd docker

恢复数据目录

安装完docker-ce后,系统会创建新的docker目录,删除新的,如何把备份的改回docker名称。
切记:不要启动docker!!

rm -rf /var/lib/docker
mv /var/lib/docker-bak /var/lib/docker

启动docker服务

systemctl enable containerd

docker -v
Docker version 26.1.0, build 9714adc

ctr version
Client:
  Version:  1.6.31
  Revision: e377cd56a71523140ca6ae87e30244719194a521
  Go version: go1.21.9

Server:
  Version:  1.6.31
  Revision: e377cd56a71523140ca6ae87e30244719194a521
  UUID: 07d08019-3523-4f01-90db-367b21874598

cat /etc/containerd/config.toml

报错1
Error response from daemon: Unknown runtime specified docker-runc
需要针对容器里面的docker-runc改一下名称,用runc替换docker-runc。
grep -rl ‘docker-runc’ /var/lib/docker/containers/ | xargs sed -i ‘s/docker-runc/runc/g’
systemctl restart docker

报错1
level=error msg="failed to initialize a tracing processor \"otlp\"" error="no OpenTelemetry endpoint: skip plugin"
使用
systemctl start containerd
不要用
systemctl start docker

2.安装docker-compose:

https://github.com/docker/compose/releases
安装方式

  • 二进制安装docker-compose
  • yum方式安装docker-compose
  • python3+pip 安装

二进制方式安装docker-compose:

简单快速

wget https://github.com/docker/compose/releases/download/v2.12.2/docker-compose-linux-x86_64
wget https://github.com/docker/compose/releases/download/v2.22.0/docker-compose-linux-x86_64
sudo cp -arf docker-compose-linux-x86_64 /usr/bin/docker-compose
sudo chmod +x /usr/bin/docker-compose
ln -s /usr/bin/docker-compose /usr/local/bin/docker-compose

卸载
sudo rm /usr/bin/docker-compose

yum方式安装docker-compose:

安装复杂

相关包安装

yum -y install libjpeg zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel
yum install -y libffi-devel zlib1g-dev

openssl升级

centos7默认的openssl版本和python3.10以上的版本不兼容
openssl version

OpenSSL 1.0.2k-fips  26 Jan 2017
wget https://www.openssl.org/source/openssl-1.1.1q.tar.gz
tar -zxvf openssl-1.1.1q.tar.gz
cd openssl-1.1.1q
./config --prefix=/usr/local/openssl 
make -j && make install

ln -s /usr/local/openssl/lib/libcrypto.so.1.1  /usr/lib64/libcrypto.so.1.1
ln -s /usr/local/openssl/lib/libssl.so.1.1 /usr/lib64/libssl.so.1.1
/usr/local/openssl/bin/openssl version
OpenSSL 1.1.1q  5 Jul 2022

备份原来的openssl文件,可通过whereis openssl查询位置

mv /usr/bin/openssl /usr/bin/openssl.old
mv /usr/include/openssl /usr/include/openssl.old

用新的文件替换旧的文件,执行命令如下:

ln -sf /usr/local/openssl/bin/openssl /usr/bin/openssl
ln -s /usr/local/openssl/include/openssl /usr/include/openssl

openssl version
OpenSSL 1.1.1q  5 Jul 2022
python3+pip 安装
yum install epel-release 
yum install -y python3 python3-pip python3-devel

pip3 –version

pip 9.0.3 from /usr/lib/python3.6/site-packages (python 3.6)
pip 国内镜像加速
mkdir ~/.pip/
vi ~/.pip/pip.conf
[global]
index-url = http://mirrors.aliyun.com/pypi/simple/
trusted-host = mirrors.aliyun.com         
disable-pip-version-check = true        
timeout = 120
pip升级
pip3 install --upgrade pip --trusted-host mirrors.aliyun.com

pip3 –version
WARNING: pip is being invoked by an old script wrapper. This will fail in a future version of pip.
Please see https://github.com/pypa/pip/issues/5599 for advice on fixing the underlying issue.
To avoid this problem you can invoke Python with ‘-m pip’ instead of running pip directly.
pip 21.3.1 from /usr/local/lib/python3.6/site-packages/pip (python 3.6)

docker-compose 安装
pip3 install docker-compose --trusted-host mirrors.aliyun.com

ln -s /usr/local/python3/bin/docker-compose /usr/bin/docker-compose 

docker-compose version
/usr/local/lib/python3.6/site-packages/paramiko/transport.py:32: CryptographyDeprecationWarning: Python 3.6 is no longer supported by the Python core team. Therefore, support for it is deprecated in cryptography. The next release of cryptography will remove support for Python 3.6.
  from cryptography.hazmat.backends import default_backend
docker-compose version 1.29.2, build unknown
docker-py version: 5.0.3
CPython version: 3.6.8
OpenSSL version: OpenSSL 1.0.2k-fips  26 Jan 2017
docker-compose 卸载

pip uninstall docker-compose

安装错误

setuptools-rust

File "/tmp/pip-build-6plwm63o/bcrypt/setup.py", line 11, in <module>
        from setuptools_rust import RustExtension
    ModuleNotFoundError: No module named 'setuptools_rust'
pip3 install setuptools-rust
The wheel package is not available.
pip3 install wheel

cffi

Could not find a version that satisfies the requirement cffi>=1.4.1 (from versions: )
pip3 install cffi
Successfully installed cffi-1.15.1 pycparser-2.21

Rust

his package requires Rust >=1.48.0.
pip3 install Rust

zlib,bzip

configure: error: zlib development files not found
yum install zlib zlib-devel
yum install bzip2 bzip2-devel bzip2-libs

libjpeg

The headers or library files could not be found for jpeg,
    a required dependency when compiling Pillow from source.

yum install libjpeg zlib libtiff

3.harbor 安装

准备文件

wget https://github.com/goharbor/harbor/releases/download/v2.8.4/harbor-offline-installer-v2.8.4.tgz
tar xf harbor-offline-installer-v2.8.4.tgz
mv harbor /usr/local/
cd /usr/local/
cd harbor
cp harbor.yml.tmpl harbor.yml

设定访问域名,端口,admin密码,db密码,存储目录

vi harbor.yml
hostname: repo.k8s.local
http:
    port:5100
#https:
  # https port for harbor, default is 443
  #port: 443
  # The path of cert and key files for nginx
  #certificate: /your/certificate/path
  #private_key: /your/private/key/path

harbor_admin_password: Harbor12345

database:
  # The password for the root user of Harbor DB. Change this before any production use.
  password: root123

# The default data volume
data_volume: /data_harbor

初始化

其实这个prepare的作用是用来初始化将harbor.yml转化为/usr/local/harbor/docker-compose.yml文件

./prepare

prepare base dir is set to /usr/local/harbor
Unable to find image 'goharbor/prepare:v2.8.4' locally
v2.8.4: Pulling from goharbor/prepare
b73ab88bdeef: Pull complete 
0a4647ff4f26: Pull complete 
ac87c0a6beec: Pull complete 
58290933e402: Pull complete 
2dd75ae2b8d6: Pull complete 
0432d14b35c2: Pull complete 
1d94d426c05b: Pull complete 
9242105872e7: Pull complete 
7079d6fb028f: Pull complete 
e3e737964616: Pull complete 
Digest: sha256:80837b160b3a876748c4abb68b35389485b4ddcd5de39bb82a7541d3f3051cae
Status: Downloaded newer image for goharbor/prepare:v2.8.4
WARNING:root:WARNING: HTTP protocol is insecure. Harbor will deprecate http protocol in the future. Please make sure to upgrade to https
Generated configuration file: /config/portal/nginx.conf
Generated configuration file: /config/log/logrotate.conf
Generated configuration file: /config/log/rsyslog_docker.conf
Generated configuration file: /config/nginx/nginx.conf
Generated configuration file: /config/core/env
Generated configuration file: /config/core/app.conf
Generated configuration file: /config/registry/config.yml
Generated configuration file: /config/registryctl/env
Generated configuration file: /config/registryctl/config.yml
Generated configuration file: /config/db/env
Generated configuration file: /config/jobservice/env
Generated configuration file: /config/jobservice/config.yml
Generated and saved secret to file: /data/secret/keys/secretkey
Successfully called func: create_root_cert
Generated configuration file: /compose_location/docker-compose.yml
Clean up the input dir

开始安装

./install.sh
[Step 0]: checking if docker is installed ...

Note: docker version: 24.0.6

[Step 1]: checking docker-compose is installed ...

Note: Docker Compose version v2.21.0

[Step 2]: loading Harbor images ...
a074a02dfff1: Loading layer [==================================================>]  37.79MB/37.79MB
a1845a3d89a2: Loading layer [==================================================>]  9.188MB/9.188MB
3f06bc32288c: Loading layer [==================================================>]  3.584kB/3.584kB
245244bd15d4: Loading layer [==================================================>]   2.56kB/2.56kB
42ca8ea5af72: Loading layer [==================================================>]  47.58MB/47.58MB
8d1a6771e613: Loading layer [==================================================>]  48.37MB/48.37MB
Loaded image: goharbor/harbor-jobservice:v2.8.4
9e404a035c29: Loading layer [==================================================>]  84.62MB/84.62MB
8a45a3e2d467: Loading layer [==================================================>]  3.072kB/3.072kB
50103680c597: Loading layer [==================================================>]   59.9kB/59.9kB
7da34aa8a12d: Loading layer [==================================================>]  61.95kB/61.95kB
Loaded image: goharbor/redis-photon:v2.8.4
5d6d0147b133: Loading layer [==================================================>]  89.19MB/89.19MB
f7f30f0432f2: Loading layer [==================================================>]  3.584kB/3.584kB
b895ffa154de: Loading layer [==================================================>]  3.072kB/3.072kB
9fb8c7a01498: Loading layer [==================================================>]   2.56kB/2.56kB
8a232dc48045: Loading layer [==================================================>]  3.072kB/3.072kB
839e0de14204: Loading layer [==================================================>]  3.584kB/3.584kB
3f683bb644b2: Loading layer [==================================================>]  20.48kB/20.48kB
Loaded image: goharbor/harbor-log:v2.8.4
627fc8f29b12: Loading layer [==================================================>]  115.9MB/115.9MB
b4faf8a74f36: Loading layer [==================================================>]   25.2MB/25.2MB
22c2b4c49c70: Loading layer [==================================================>]   5.12kB/5.12kB
98c144348806: Loading layer [==================================================>]  6.144kB/6.144kB
6f34146f1977: Loading layer [==================================================>]  3.072kB/3.072kB
8dd9b9af7425: Loading layer [==================================================>]  2.048kB/2.048kB
04498149158d: Loading layer [==================================================>]   2.56kB/2.56kB
7600d3f327f6: Loading layer [==================================================>]   2.56kB/2.56kB
e30935897ec8: Loading layer [==================================================>]   2.56kB/2.56kB
b91c1501abe9: Loading layer [==================================================>]  9.728kB/9.728kB
Loaded image: goharbor/harbor-db:v2.8.4
736147cbb70a: Loading layer [==================================================>]  81.13MB/81.13MB
Loaded image: goharbor/nginx-photon:v2.8.4
3ee113d617fa: Loading layer [==================================================>]  72.75MB/72.75MB
8f8c635f3d64: Loading layer [==================================================>]  38.64MB/38.64MB
50ede47ef7b6: Loading layer [==================================================>]  19.94MB/19.94MB
bbe4550fbed9: Loading layer [==================================================>]  65.54kB/65.54kB
6a6c08954476: Loading layer [==================================================>]   2.56kB/2.56kB
4fcee09b3045: Loading layer [==================================================>]  1.536kB/1.536kB
cd9e13a0fadf: Loading layer [==================================================>]  12.29kB/12.29kB
5c4cf244ed4a: Loading layer [==================================================>]  2.123MB/2.123MB
2f207d2f7a63: Loading layer [==================================================>]  419.8kB/419.8kB
Loaded image: goharbor/prepare:v2.8.4
e4e75b52265a: Loading layer [==================================================>]  9.188MB/9.188MB
6ca0b8687881: Loading layer [==================================================>]  3.584kB/3.584kB
2efe438491fa: Loading layer [==================================================>]   2.56kB/2.56kB
6c8c2dc9cf24: Loading layer [==================================================>]  59.31MB/59.31MB
70aa7368b062: Loading layer [==================================================>]  5.632kB/5.632kB
1ad1e6d7b7f2: Loading layer [==================================================>]  116.7kB/116.7kB
fdf3c64c43d4: Loading layer [==================================================>]  44.03kB/44.03kB
af312371ff9e: Loading layer [==================================================>]  60.26MB/60.26MB
2ef0db7a0b49: Loading layer [==================================================>]   2.56kB/2.56kB
Loaded image: goharbor/harbor-core:v2.8.4
0cbd65e4d842: Loading layer [==================================================>]  6.699MB/6.699MB
dfd5a1cf5002: Loading layer [==================================================>]  4.096kB/4.096kB
793940424064: Loading layer [==================================================>]  3.072kB/3.072kB
44888bf86da0: Loading layer [==================================================>]    196MB/196MB
561960448b05: Loading layer [==================================================>]   14.1MB/14.1MB
deb1d83b4cbd: Loading layer [==================================================>]  210.9MB/210.9MB
Loaded image: goharbor/trivy-adapter-photon:v2.8.4
dd52e9dde638: Loading layer [==================================================>]  81.13MB/81.13MB
8cfe6bb78139: Loading layer [==================================================>]    6.1MB/6.1MB
8aebde8774f2: Loading layer [==================================================>]  1.233MB/1.233MB
Loaded image: goharbor/harbor-portal:v2.8.4
e2bb7b6f858e: Loading layer [==================================================>]  6.172MB/6.172MB
b58529f5727f: Loading layer [==================================================>]  4.096kB/4.096kB
15b87640160a: Loading layer [==================================================>]  3.072kB/3.072kB
f8cc13293a41: Loading layer [==================================================>]  17.57MB/17.57MB
51175195e0e4: Loading layer [==================================================>]  18.36MB/18.36MB
Loaded image: goharbor/registry-photon:v2.8.4
8c3c80de8e46: Loading layer [==================================================>]  6.167MB/6.167MB
ba247990a26d: Loading layer [==================================================>]  9.143MB/9.143MB
78c730633955: Loading layer [==================================================>]  15.88MB/15.88MB
901f70ff7f25: Loading layer [==================================================>]  29.29MB/29.29MB
e91438791db8: Loading layer [==================================================>]  22.02kB/22.02kB
eb4f8ee41ee3: Loading layer [==================================================>]  15.88MB/15.88MB
Loaded image: goharbor/notary-server-photon:v2.8.4
d3bc6746e3a0: Loading layer [==================================================>]  6.167MB/6.167MB
e9dc9957d190: Loading layer [==================================================>]  9.143MB/9.143MB
6548f7c0890e: Loading layer [==================================================>]  14.47MB/14.47MB
8ab2eab06c9c: Loading layer [==================================================>]  29.29MB/29.29MB
475002e6da05: Loading layer [==================================================>]  22.02kB/22.02kB
70a417415ad1: Loading layer [==================================================>]  14.47MB/14.47MB
Loaded image: goharbor/notary-signer-photon:v2.8.4
bfe8ceaf89b9: Loading layer [==================================================>]  6.172MB/6.172MB
cf503352618a: Loading layer [==================================================>]  4.096kB/4.096kB
21e09698bb69: Loading layer [==================================================>]  17.57MB/17.57MB
7afc834ab33e: Loading layer [==================================================>]  3.072kB/3.072kB
14752e2b2fbf: Loading layer [==================================================>]  31.13MB/31.13MB
8daa88c089ea: Loading layer [==================================================>]  49.49MB/49.49MB
Loaded image: goharbor/harbor-registryctl:v2.8.4
4b4afa104b42: Loading layer [==================================================>]  9.188MB/9.188MB
4ef2e0c082a7: Loading layer [==================================================>]  26.03MB/26.03MB
8eb9f5ee0436: Loading layer [==================================================>]  4.608kB/4.608kB
d449c6ac0cd4: Loading layer [==================================================>]  26.82MB/26.82MB
Loaded image: goharbor/harbor-exporter:v2.8.4

[Step 3]: preparing environment ...

[Step 4]: preparing harbor configs ...
prepare base dir is set to /root/src/harbor
WARNING:root:WARNING: HTTP protocol is insecure. Harbor will deprecate http protocol in the future. Please make sure to upgrade to https
Generated configuration file: /config/portal/nginx.conf
Generated configuration file: /config/log/logrotate.conf
Generated configuration file: /config/log/rsyslog_docker.conf
Generated configuration file: /config/nginx/nginx.conf
Generated configuration file: /config/core/env
Generated configuration file: /config/core/app.conf
Generated configuration file: /config/registry/config.yml
Generated configuration file: /config/registryctl/env
Generated configuration file: /config/registryctl/config.yml
Generated configuration file: /config/db/env
Generated configuration file: /config/jobservice/env
Generated configuration file: /config/jobservice/config.yml
Generated and saved secret to file: /data/secret/keys/secretkey
Successfully called func: create_root_cert
Generated configuration file: /compose_location/docker-compose.yml
Clean up the input dir

Note: stopping existing Harbor instance ...

[Step 5]: starting Harbor ...
[+] Running 1/1

--Harbor has been installed and started successfully.----

测试

在外部机器,本机,k8s节点中修改host文件,增加指向
192.168.244.6 repo.k8s.local

vi /etc/hosts

192.168.244.6 repo.k8s.local

在浏览器访问 http://repo.k8s.local:5100/

输入初始密码登录
admin/Harbor12345

忘记密码

docker ps

f11056420a99   goharbor/harbor-core:v2.8.4          "/harbor/entrypoint.…"   3 weeks ago    Up About an hour (healthy)                                                                                        harbor-core  
f69e921a4464   goharbor/harbor-db:v2.8.4            "/docker-entrypoint.…"   3 weeks ago    Up About an hour (healthy)                                                                                        harbor-db                                                                                   

方式一 查看yaml密码

cat /usr/local/harbor/harbor.yml|grep password

harbor_admin_password: Harbor12345
  # The password for the root user of Harbor DB. Change this before any production use.
  password: local_ROOT_!!88

方式二 容器内查看

第一步、 进入容器
docker exec -it "" bash
docker exec -it "f11056420a99" bash

第二步、查看密码
env | grep HARBOR_ADMIN_PASSWORD

HARBOR_ADMIN_PASSWORD=Harbor12345

重置 admin 密码
docker exec -it "" bash
docker exec -it "f69e921a4464" bash

psql -U postgres -d registry
> select * from harbor_user;
> update harbor_user set salt='', password='' where user_id = "<admin user_id>";  
exit

重新启动Harbor私有镜像仓库后,密码就会自动重置为之前安装时配置的Harbor12345

重新启动Harbor私有镜像仓库

# docker-compose down
#./prepare 
# docker-compose up -d

docker-compose ps
no configuration file provided: not found
最常见的原因是没有在docker-compose.yml文件的路径下执行该命令。

cd /usr/local/harbor/
docker-compose ps

web登录时会一直提示用户名密码错误

如果之前清理过镜像可能把镜像删除了。

docker-compose down
./prepare 
prepare base dir is set to /usr/local/harbor
Unable to find image 'goharbor/prepare:v2.8.4' locally
docker-compose up -d

项目用户角色说明

受限访客:受限访客没有项目的完全读取权限。他们可以拉取镜像但不能推送,而且他们看不到日志或项目的其他成员。例如,你可以为来自不同组织的共享项目访问权限的用户创建受限访客。
访客:访客对指定项目具有只读权限。他们可以拉取和重新标记镜像,但不能推送。
开发者:开发者拥有项目的读写权限。
维护者:维护者拥有超越“开发者”的权限,包括扫描镜像、查看复制作业以及删除镜像和helm charts的能力。
项目管理员:创建新项目时,你将被分配给项目的“ProjectAdmin”角色。“ProjectAdmin”除了读写权限外,还有一些管理权限,如添加和删除成员、启动漏洞扫描等。

新建用户

用户管理/创建用户

k8s_user1
k8s_Uus1

k8s_pull
k8s_Pul1

项目

将项目设为公开,并将用户加入项目
library 公开
项目/成员/+用户
k8s_user1
维护者
k8s_pull
访客

项目/新建
k8s 公开
项目/成员/+用户
k8s_user1
维护者
k8s_pull
访客

项目命名规则
方式一 全地址做对应,前面增加私仓地址
docker.io/library/nginx:1.21.4
docker tag docker.io/library/nginx:1.21.4 repo.k8s.local/docker.io/library/nginx:1.21.4

方式二 忽略域名,目录对应
docker.io/library/nginx:1.21.4
docker tag docker.io/library/nginx:1.21.4 repo.k8s.local/library/nginx:1.21.4

方式三 忽略域名和目录,镜像对应
按属性放入目录,如基础服务放入google_containers,组件放library ,应用放app
repo.k8s.local/library/nginx:1.21.4
docker tag docker.io/library/nginx:1.21.4 repo.k8s.local/library/nginx:1.21.4

关闭:

cd /usr/local/harbor/

docker-compose down -v   
ERROR: 
        Can't find a suitable configuration file in this directory or any
        parent. Are you in the right directory?

        Supported filenames: docker-compose.yml, docker-compose.yaml, compose.yml, compose.yaml

cd /usr/local/harbor
docker-compose down -v   

开启:

cd /usr/local/harbor/
docker-compose up -d

Creating network "harbor_harbor" with the default driver
Creating harbor-log ... done
Creating harbor-portal ... done
Creating registry      ... done
Creating registryctl   ... done
Creating harbor-db     ... done
Creating redis         ... done
Creating harbor-core   ... done
Creating nginx             ... done
Creating harbor-jobservice ... done
docker ps
CONTAINER ID   IMAGE                                COMMAND                  CREATED         STATUS                   PORTS                                       NAMES
7ee76b324f96   goharbor/harbor-jobservice:v2.8.4    "/harbor/entrypoint.…"   3 minutes ago   Up 3 minutes (healthy)                                               harbor-jobservice
e1f9af0dfec1   goharbor/nginx-photon:v2.8.4         "nginx -g 'daemon of…"   3 minutes ago   Up 3 minutes (healthy)   0.0.0.0:5100->8080/tcp, :::5100->8080/tcp   nginx
55212a4181c5   goharbor/harbor-core:v2.8.4          "/harbor/entrypoint.…"   3 minutes ago   Up 3 minutes (healthy)                                               harbor-core
bfd166244ad3   goharbor/redis-photon:v2.8.4         "redis-server /etc/r…"   3 minutes ago   Up 3 minutes (healthy)                                               redis
beb5c0c77832   goharbor/harbor-registryctl:v2.8.4   "/home/harbor/start.…"   3 minutes ago   Up 3 minutes (healthy)                                               registryctl
17bd8d7f8a02   goharbor/harbor-db:v2.8.4            "/docker-entrypoint.…"   3 minutes ago   Up 3 minutes (healthy)                                               harbor-db
c7c665923196   goharbor/registry-photon:v2.8.4      "/home/harbor/entryp…"   3 minutes ago   Up 3 minutes (healthy)                                               registry
a08329e11be2   goharbor/harbor-portal:v2.8.4        "nginx -g 'daemon of…"   3 minutes ago   Up 3 minutes (healthy)                                               harbor-portal
d8716d3159a0   goharbor/harbor-log:v2.8.4           "/bin/sh -c /usr/loc…"   3 minutes ago   Up 3 minutes (healthy)   127.0.0.1:1514->10514/tcp                   harbor-log

注册成服务

cat > /lib/systemd/system/harbor.service <<EOF
[Unit]
Description=Harbor
After=docker.service systemd-networkd.service systemd-resolved.service
Requires=docker.service
Documentation=http://github.com/vmware/harbor

[Service]
Type=simple
Restart=on-failure
RestartSec=5
ExecStart=/usr/local/bin/docker-compose -f /usr/local/harbor/docker-compose.yml up
ExecStop=/usr/local/bin/docker-compose -f /usr/local/harbor/docker-compose.yml down

[Install]
WantedBy=multi-user.target
EOF

开机启动

systemctl daemon-reload 
systemctl status harbor
systemctl stop harbor
systemctl start harbor
systemctl enable harbor

防火墙

iptables -A INPUT -p tcp -m tcp --dport 5100 -j ACCEPT
iptabes-save

配置对Harbor的HTTPS访问

注意一旦启用https 那么http会强跳到https,http不再可用
要配置HTTPS,必须创建SSL证书。您可以使用由受信任的第三方CA签名的证书,也可以使用openssl进行自签名证书。
本节介绍如何使用 ​ ​OpenSSL​​​创建CA,以及如何使用CA签署服务器证书和客户端证书。您可以使用其他CA工具进行自签名
在生产环境中,一般是应该从CA获得证书,例如:在阿里云购买域名之后就可以下载相关域名的CA证书了。但是在测试或开发环境中,对于这种自己定义的内网域名,就可以自己生成自己的CA证书。

1. 生成CA证书私钥 ca.key。Generate a CA certificate private key.

openssl genrsa -out ca.key 4096

2. 根据上面生成的CA证书私钥,再来生成CA证书 ca.crt。 Generate the CA certificate.

设置 ​​-subj​​ 选项中的值来反映的组织,例如:省份、地市、域名等等信息。如果使用FQDN 【 (Fully Qualified Domain Name)全限定域名:同时带有主机名和域名的名称。】连接Harbor主机,则必须将其指定为通用名称(​​CN​​​)属性,可以看到示例写的是​​yourdomain.com​​。

openssl req -x509 -new -nodes -sha512 -days 3650 \
 -subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=repo.k8s.local" \
 -key ca.key \
 -out ca.crt

 # 参数说明:
-new 指生成证书请求
-x509 表示直接输出证书
-key 指定私钥文件
-days 指定证书过期时间为3650天
-out 导出结束后证书文件
-subj 输入证书拥有者信息
生成服务器证书 Generate a Server Certificate

证书通常包含一个​​.crt​​​文件和一个​​.key​​​文件,例如​​yourdomain.com.crt​​​和​​yourdomain.com.key​​。

在这里,因为我上面设置的服务器域名为repo.k8s.local​​​,所以将要生成的证书为repo.k8s.local.crt​​​ 和 repo.k8s.local.key​​。

1.生成CA证书私钥
openssl genrsa -out harbor.key 4096
2.生成证书签名请求(CSR)

注意下使用repo.k8s.local.key 和 repo.k8s.local.csr

openssl req -sha512 -new \
    -subj "/C=CN/ST=Beijing/L=Beijing/O=example/OU=Personal/CN=repo.k8s.local" \
    -key harbor.key \
    -out harbor.csr
3.生成一个x509 v3扩展文件。Generate an x509 v3 extension file.
cat > v3.ext <<-EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1=repo.k8s.local
DNS.2=repo.k8s
EOF
4. 使用该​​v3.ext​​​文件为您的Harbor主机生成证书 yourdomain.com.crt。
openssl x509 -req -sha512 -days 3650 \
    -extfile v3.ext \
    -CA ca.crt -CAkey ca.key -CAcreateserial \
    -in harbor.csr \
    -out repo.k8s.local.crt

将服务器证书​​yourdomain.com.crt​​​和密钥​​yourdomain.com.key​​复制到Harbor主机上的certficates文件夹中。

mkdir /usr/local/harbor/certificate
cp repo.k8s.local.crt /usr/local/harbor/certificate/
cp harbor.key /usr/local/harbor/certificate/

双机时也复制到从机

scp  /usr/local/harbor/certificate/* [email protected]:.

编辑配置,打开https支持

vi  /usr/local/harbor/harbor.yml
https:
  # https port for harbor, default is 443
  port: 443
  # The path of cert and key files for nginx
  certificate: /usr/local/harbor/certificate/repo.k8s.local.crt 
  private_key: /usr/local/harbor/certificate/harbor.key
cd /usr/local/harbor/
./prepare 
#重新生成/usr/local/harbor/docker-compose.yml

systemctl daemon-reload 
systemctl stop harbor
systemctl start harbor
systemctl status harbor

netstat -lntp
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      31217/docker-proxy  
tcp        0      0 127.0.0.1:1514          0.0.0.0:*               LISTEN      30700/docker-proxy  
tcp        0      0 0.0.0.0:5100            0.0.0.0:*               LISTEN      31235/docker-proxy  

防火墙

iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
iptabes-save

http://repo.k8s.local:5100

https://repo.k8s.local

在浏览器访问,使用nat 5443指到192.168.244.6:443
https://repo.k8s.local:5443/

docker
将服务器证书​​yourdomain.com.crt​​​的编码格式转换为​​yourdomain.com.cert​​​,提供Docker使用

openssl x509 -inform PEM -in repo.k8s.local.crt -out repo.k8s.local.cert

mkdir -p /etc/docker/certs.d/repo.k8s.local/
cp repo.k8s.local.cert /etc/docker/certs.d/repo.k8s.local/
cp harbor.key /etc/docker/certs.d/repo.k8s.local/repo.k8s.local.key
cp ca.crt /etc/docker/certs.d/repo.k8s.local/

双机时也复制到从机

scp  /etc/docker/certs.d/repo.k8s.local/* [email protected]:.

测试docker登录

docker login repo.k8s.local
Username: k8s_user1
Password: k8s_Uus1

修改http为https
vi /etc/docker/daemon.json

#"insecure-registries":["repo.k8s.local:5100"],
"insecure-registries":["https://repo.k8s.local"],

错误
ctr: failed to resolve reference "xxx.local/library/docker/getting-started
需要拷贝一份上面harbor的ca到系统ca目录并更新
cp ca.crt /usr/local/share/ca-certificates/
/usr/sbin/update-ca-certificates

错误
Error response from daemon: missing client certificate harbor.cert for key harbor.key
注意 harbor.key key文件名和 cert一致

错误

Error response from daemon: Get "https://repo.k8s.local/v2/": Get "https://repo.k8s.local:5433/service/token?account=k8s_user1&client_id=docker&offline_token=true&service=harbor-registry": dial tcp 192.168.244.6:5433: connect: connection refused

harbor配制文件/usr/local/harbor/harbor.yml
修正注释掉 external_url: https://repo.k8s.local:5433

错误
Error response from daemon: Get "https://repo.k8s.local/v2/": tls: failed to verify certificate: x509: certificate signed by unknown authority

错误
Job harbor.service/start failed with result ‘dependency’.

systemctl staart harbor
systemctl status harbor

ctr测试推送

ctr -n k8s.io images ls  |grep busybox
repo.k8s.local:5100/google_containers/busybox:9.9                                                                                       application/vnd.docker.distribution.manifest.v2+json      sha256:023917ec6a886d0e8e15f28fb543515a5fcd8d938edb091e8147db4efed388ee 2.1 MiB   linux/amd64   

ctr -n k8s.io i tag  repo.k8s.local:5100/google_containers/busybox:9.9 repo.k8s.local/google_containers/busybox:9.9

ctr -n k8s.io i push --user k8s_user1:k8s_Uus1 repo.k8s.local/google_containers/busybox:9.9 
ctr: failed to do request: Head "https://repo.k8s.local/v2/google_containers/busybox/blobs/sha256:a416a98b71e224a31ee99cff8e16063554498227d2b696152a9c3e0aa65e5824": tls: failed to verify certificate: x509: certificate signed by unknown authority

#解决办法1.指定 -k 参数跳过证书校验。
ctr -n k8s.io i push --user k8s_user1:k8s_Uus1 -k repo.k8s.local/google_containers/busybox:9.9 

# 解决办法2.指定CA证书、Harbor 相关证书文件路径。
#将harbor的ca.crt 复制到当前节点
scp /root/src/harbor/ca.crt [email protected]:.
ctr -n k8s.io i push --user k8s_user1:k8s_Uus1 --tlscacert ca.crt repo.k8s.local/google_containers/busybox:9.9 

准备测试创建pod文件
vi test-harbor.yaml

# test-harbor.yaml
apiVersion: v1
kind: Pod
metadata:
  name: harbor-registry-test
spec:
  containers:
  - name: test
    image: repo.k8s.local/google_containers/busybox:9.9 
    args:
    - sleep
    - "3600"
  imagePullSecrets:
  - name: harbor-auth

创建pod
kubectl apply -f test-harbor.yaml

pod/harbor-registry-test created

查看
kubectl describe pod harbor-registry-test

Name:             harbor-registry-test
Namespace:        default
Priority:         0
Service Account:  default
Node:             node01.k8s.local/192.168.244.5
Start Time:       Mon, 16 Oct 2023 17:32:15 +0800
Labels:           
Annotations:      
Status:           Running
IP:               10.244.1.4
IPs:
  IP:  10.244.1.4
Containers:
  test:
    Container ID:  containerd://5fa473b370c56d71f0466e14960a974ead4559106495a79eb9b2a21a7ecee52f
    Image:         repo.k8s.local/google_containers/busybox:9.9
    Image ID:      repo.k8s.local/google_containers/busybox@sha256:023917ec6a886d0e8e15f28fb543515a5fcd8d938edb091e8147db4efed388ee
    Port:          

kubectl create secret docker-registry harbor-auth –docker-server=https://repo.k8s.local –docker-username=k8s_pull –docker-password=k8s_Pul1 –[email protected] -n default

k8s节点配置

containerd 配置私有仓库
Containerd 目前没有直接配置镜像加速的功能,但 containerd 中可以修改 docker.io 对应的 endpoint,所以可以通过修改 endpoint 来实现镜像加速下载。因为 endpoint 是轮询访问,所以可以给 docker.io 配置多个仓库地址来实现 加速地址+默认仓库地址

注意:这个配置文件是给crictl和kubelet使用,ctr是不可以用这个配置文件的,ctr 不使用 CRI,因此它不读取 plugins."io.containerd.grpc.v1.cri"配置。
直接修改:/etc/containerd/config.toml配置文件,这种方式在较新版本的contaienrd中已经被废弃,将来肯定会被移除,
两者取一
https://github.com/containerd/cri/blob/master/docs/registry.md
[plugins."io.containerd.grpc.v1.cri".registry.configs."repo.k8s.local".tls]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
和 config_path 会冲突

方式一 registry.mirrors
vi /etc/containerd/config.toml

[plugins."io.containerd.grpc.v1.cri".registry.configs]
      [plugins."io.containerd.grpc.v1.cri".registry.configs."repo.k8s.local".tls]
        insecure_skip_verify = true
      [plugins."io.containerd.grpc.v1.cri".registry.configs."repo.k8s.local".auth]
        username = "k8s_pull"
        password = "k8s_Pul1"

[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
      [plugins."io.containerd.grpc.v1.cri".registry.mirrors."repo.k8s.local"]
        endpoint = ["http://repo.k8s.local:5100"]
      [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
        endpoint = ["https://registry.cn-hangzhou.aliyuncs.com"]

保存并关闭配置文件。

方式二 config_path
vi /etc/containerd/config.toml

[plugins."io.containerd.grpc.v1.cri".registry]
   config_path = "/etc/containerd/certs.d"
      [plugins."io.containerd.grpc.v1.cri".registry.configs."repo.k8s.local".auth]
        username = "k8s_pull"
        password = "k8s_Pul1"
#注意创建的目录即为configs后面填写的内容
mkdir -p /etc/containerd/certs.d/docker.io/

cat > /etc/containerd/certs.d/docker.io/hosts.toml <
http/https两者取一配制

mkdir -p /etc/containerd/certs.d/repo.k8s.local

#harbor私仓使用http方式
cat > /etc/containerd/certs.d/repo.k8s.local/hosts.toml <
#harbor私仓使用http 非常规端口方式
cat > /etc/containerd/certs.d/repo.k8s.local:5100/hosts.toml <

从harbor复制证书到节点
scp [email protected]:/etc/docker/certs.d/repo.k8s.local/* /etc/containerd/certs.d/repo.k8s.local/

#harbor私仓使用https方式 带证书
cat > /etc/containerd/certs.d/repo.k8s.local/hosts.toml <
#harbor私仓使用https方式
cat > /etc/containerd/certs.d/repo.k8s.local/hosts.toml <

重新启动containerd服务以使更改生效。可以使用以下命令之一:
使用systemd:

systemctl daemon-reload
systemctl restart containerd
systemctl status containerd

使用Docker Compose(如果您是使用Docker Compose运行的):
docker-compose restart

现在,containerd将使用您配置的私有Harbor源作为容器镜像的默认来源。您可以验证配置是否生效,通过拉取和运行一个位于Harbor Registry上的镜像来测试。

在harbor推送证书到节点
从harbor复制证书到节点
scp [email protected]:/etc/docker/certs.d/repo.k8s.local/* /etc/containerd/certs.d/repo.k8s.local/

节点上测试
ctr -n k8s.io i pull --user k8s_user1:k8s_Uus1 --tlscacert /etc/containerd/certs.d/repo.k8s.local/ca.crt repo.k8s.local/google_containers/busybox:9.9
ctr -n k8s.io images ls

ctr -n k8s.io i pull --user k8s_user1:k8s_Uus1 -k repo.k8s.local/google_containers/busybox:9.9

https 私库

ctr -n k8s.io i push --user k8s_user1:k8s_Uus1 -k repo.k8s.local/google_containers/busybox:9.9

推送到http

ctr -n k8s.io i push --user k8s_user1:k8s_Uus1 --plain-http repo.k8s.local/google_containers/busybox:9.9

ctr image pull --platform linux/amd64 docker.io/library/nginx:1.18.0

jq安装

jq安装
https://pkgs.org/centos-7/epel-x86_64/jq-1.5-1.el7.x86_64.rpm.html

wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
rpm -ivh epel-release-latest-7.noarch.rpm
yum install jq
  Installing : oniguruma-6.8.2-2.el7.x86_64                                                                                    1/2 
  Installing : jq-1.6-2.el7.x86_64                                                                                             2/2

卸载

卸载harbor步骤:(针对脚本一键安装)

docker-compose down   #停止 docker-compose 
rm -rf /data_harbor *    #删除挂载的harbor持久化数据的目录内容
rm -rf /opt/harbor   #删除harbor目录
docker-compose up -d   #重启

配置Harbor的高可用(双组复制)

新建用户
admin_sync/sync_9OK

新建目标(仓库管理-新建):
目标名:s2
url:https://10.100.5.6
用户名:admin
密码:Harbor12345
远程验证:x
连接测试:√

新建规则:
登陆S1的Harbor管理页面,进入kubernetes项目
点击“复制”,新建规则
名称:cp_to_s2
目标:https://10.100.5.6
触发模式:即刻

在S2的Harbor做相同配置

harbor-连接其他仓库报错
pkg/reg/adapter/native/adapter.go:126]: failed to ping registry

docker exec -it -u root docker ps |awk '/core/{print $1}' /bin/bash
echo "192.168.244.6    repo.k8s.local">>/etc/hosts
curl http://repo.k8s.local:5100

cat > /etc/hosts <

两个harbor配制相同主机会同步失败,先将备机配成ip
vi /usr/local/harbor/harbor.yml

hostname: 10.100.5.6

# http related config
http:
  # port for http, default is 80. If https enabled, this port will redirect to https port
  port: 5100
systemctl stop harbor
cd /usr/local/harbor/
./prepare 
systemctl start harbor

harbor从机需要重新分配用户及项目的权限

各项目添加 k8s_pull 为访客
各项目添加 k8s_user1 为开发者

Posted in 安装k8s/kubernetes.

Tagged with , , .


k8s_安装3_容器

三、容器环境操作

容器选择
安装Docker或Containered

Kubernetes 默认容器运行时(CRI)为 Docker,所以需要先在各个节点中安装 Docker。另可选安装containerd
从kubernetes 1.24开始,dockershim已经从kubelet中移除,但因为历史问题docker却不支持kubernetes主推的CRI(容器运行时接口)标准,所以docker不能再作为kubernetes的容器运行时了,即从kubernetesv1.24开始不再使用docker了。

但是如果想继续使用docker的话,可以在kubelet和docker之间加上一个中间层cri-docker。cri-docker是一个支持CRI标准的shim(垫片)。一头通过CRI跟kubelet交互,另一头跟docker api交互,从而间接的实现了kubernetes以docker作为容器运行时。但是这种架构缺点也很明显,调用链更长,效率更低。
在安装Docker前需要确保操作系统内核版本为 3.10以上,因此需要CentOS7 ,CentOS7内核版本为3.10.

推荐使用containerd作为kubernetes的容器运行。

containerd配置起来比较麻烦
拉取镜像时需ctr ctrctl或安装nerdctl,推送镜像不方便
下载镜像的时候增加–all-platforms参数,譬如:ctr i pull –all-platforms,否则推送时出错,而加上–all-platforms太费带宽和空间,本来几秒的事,搞了几分钟,600多M
推送镜像的时候增加 用户和密码和–plain-http ctr i push –plain-http=true -u admin:xxxxxx ,不想-u user:password 每次必须使用 ctr pull/ctr push, 可以使用nerdctl
nerdctl 构建的机制和 docker 是完全不同的。
docker 首先会检查本地是否有 Dockerfile 中 FROM 的镜像。如果有,直接使用。没有则通过网络下载镜像;
nerdctl 会根据 Dockerfile FROM参数指定镜像的域名去网上找这个镜像,找到后确认和本地同名镜像校验无误之后,才会使用本地的镜像构建新镜像。
harbor而且要求一定要https,http不行.

方式一 安装docker

docker不支持centos6
推荐在harbor安装docker,k8s安装containered
如果之前安装过低版本docker,卸载

yum remove -y docker \
docker-client \
docker-client-latest \
docker-ce-cli \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-selinux \
docker-engine-selinux \
docker-engine

在master和node上操作

1 切换镜像源

方式一

wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo

方式二
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager \
   --add-repo \
   https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sed -i 's/download.docker.com/mirrors.aliyun.com\/docker-ce/g' /etc/yum.repos.d/docker-ce.repo
yum makecache fast

2 查看当前镜像源中支持的docker版本

yum list docker-ce --showduplicates
yum list docker-ce-cli --showduplicates

3 安装特定版本的docker-ce

kubernetes各版本对应支持的docker版本列表
https://github.com/kubernetes/kubernetes/releases
kubernetes v1.28.2 支持 docker 24.0.5 ,安装docker-ce-24.0.6-1.el7

必须指定–setopt=obsoletes=0,否则yum会自动安装更高版本

yum install –setopt=obsoletes=0 docker-ce-24.0.6-1.el7 -y

Installing:
 docker-ce                                                            x86_64                                            3:24.0.6-1.el7                                                        docker-ce-stable                                             24 M
Installing for dependencies:
 audit-libs-python                                                    x86_64                                            2.8.5-4.el7                                                           base                                                         76 k
 checkpolicy                                                          x86_64                                            2.5-8.el7                                                             base                                                        295 k
 container-selinux                                                    noarch                                            2:2.119.2-1.911c772.el7_8                                             extras                                                       40 k
 containerd.io                                                        x86_64                                            1.6.24-3.1.el7                                                        docker-ce-stable                                             34 M
 docker-buildx-plugin                                                 x86_64                                            0.11.2-1.el7                                                          docker-ce-stable                                             13 M
 docker-ce-cli                                                        x86_64                                            1:24.0.6-1.el7                                                        docker-ce-stable                                             13 M
 docker-ce-rootless-extras                                            x86_64                                            24.0.6-1.el7                                                          docker-ce-stable                                            9.1 M
 docker-compose-plugin                                                x86_64                                            2.21.0-1.el7                                                          docker-ce-stable                                             13 M
 fuse-overlayfs                                                       x86_64                                            0.7.2-6.el7_8                                                         extras                                                       54 k
 fuse3-libs                                                           x86_64                                            3.6.1-4.el7                                                           extras                                                       82 k
 libcgroup                                                            x86_64                                            0.41-21.el7                                                           base                                                         66 k
 libsemanage-python                                                   x86_64                                            2.5-14.el7                                                            base                                                        113 k
 policycoreutils-python                                               x86_64                                            2.5-34.el7                                                            base                                                        457 k
 python-IPy                                                           noarch                                            0.75-6.el7                                                            base                                                         32 k
 setools-libs                                                         x86_64                                            3.3.8-4.el7                                                           base                                                        620 k
 slirp4netns                                                          x86_64                                            0.4.3-4.el7_8                                                         extras                                                       81 k

Transaction Summary
================================================================================================================================================================================================================================================================

4 添加一个配置文件

Docker在默认情况下使用的Cgroup Driver为cgroupfs,而kubernetes推荐使用systemd来代替cgroupfs;
第二行配置第三方docker仓库

mkdir - p /etc/docker 
cat > /etc/docker/daemon.json <<EOF 
{
    "registry-mirrors":["http://hub-mirror.c.163.com"],
    "exec-opts":["native.cgroupdriver=systemd"],
    "data-root": "/var/lib/docker",
    "max-concurrent-downloads": 10,
    "max-concurrent-uploads": 5,
    "log-driver":"json-file",
    "log-opts": {
        "max-size": "300m",
        "max-file": "2"
    },
    "live-restore": true
}
EOF

5 启动docker,并设置为开机自启

systemctl daemon-reload
systemctl restart docker && systemctl enable docker

6 检查docker状态和版本

docker version
Client: Docker Engine - Community
 Version:           24.0.6
 API version:       1.43
 Go version:        go1.20.7
 Git commit:        ed223bc
 Built:             Mon Sep  4 12:35:25 2023
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          24.0.6
  API version:      1.43 (minimum version 1.12)
  Go version:       go1.20.7
  Git commit:       1a79695
  Built:            Mon Sep  4 12:34:28 2023
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.24
  GitCommit:        61f9fd88f79f081d64d6fa3bb1a0dc71ec870523
 runc:
  Version:          1.1.9
  GitCommit:        v1.1.9-0-gccaecfc
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

systemctl start docker  # 启动docker服务
systemctl stop docker  # 停止docker服务
systemctl restart docker  # 重启docker服务

#测试
sudo docker run hello-world

在所有节点安装cri-docker

yum install -y libcgroup 

wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.4/cri-dockerd-0.3.4-3.el8.x86_64.rpm

rpm -ivh cri-dockerd-0.3.4-3.el8.x86_64.rpm

vim /usr/lib/systemd/system/cri-docker.service
----
#修改第10行内容
ExecStart=/usr/bin/cri-dockerd --pod-infra-container-image=registry.aliyuncs.com/google_containers/pause:3.9 --container-runtime-endpoint fd://
----

systemctl start cri-docker
systemctl enable cri-docker

方式二 安装containerd

containerd 安装

wget https://github.com/containerd/containerd/releases/download/v1.7.11/cri-containerd-cni-1.7.11-linux-amd64.tar.gz
wget https://github.com/containerd/containerd/releases/download/v1.7.1/containerd-1.7.1-linux-amd64.tar.gz
tar xvf containerd-1.7.1-linux-amd64.tar.gz
mv bin/* /usr/local/bin/

tar xzf cri-containerd-cni-1.7.11-linux-amd64.tar.gz

#生成containerd 配置文件
mkdir /etc/containerd
containerd config default > /etc/containerd/config.toml

配置 containerd cgroup 驱动程序 systemd(所有节点)
当 systemd 是选定的初始化系统时,要将 systemd 设置为 cgroup 驱动
kubernets 自v1.24.0 后,就不再使用 docker.shim,替换采用 containerd 作为容器运行时端点

vi /etc/containerd/config.toml
#SystemdCgroup的值改为true
SystemdCgroup = true
#由于国内下载不到registry.k8s.io的镜像,修改sandbox_image的值为:
#sandbox_image = "registry.aliyuncs.com/google_containers/pause:3.9"

sed -i 's#SystemdCgroup = false#SystemdCgroup = true#g' /etc/containerd/config.toml

grep sandbox_image  /etc/containerd/config.toml
sed -i "s#registry.k8s.io/pause:3.8#registry.aliyuncs.com/google_containers/pause:3.9#g"       /etc/containerd/config.toml
grep sandbox_image  /etc/containerd/config.toml

vi /etc/containerd/config.toml

  address = "/run/containerd/containerd.sock"
    socket_path = "/var/run/nri/nri.sock"

启动containerd服务

mkdir -p /usr/local/lib/systemd/system
wget https://raw.githubusercontent.com/containerd/containerd/main/containerd.service
mv containerd.service /usr/lib/systemd/system/

cat /usr/lib/systemd/system/containerd.service 

cat > /usr/lib/systemd/system/containerd.service << EOF
# Copyright The containerd Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

[Unit]
Description=containerd container runtime
Documentation=https://containerd.io
After=network.target local-fs.target

[Service]
#uncomment to fallback to legacy CRI plugin implementation with podsandbox support.
#Environment="DISABLE_CRI_SANDBOXES=1"
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/containerd

Type=notify
Delegate=yes
KillMode=process
Restart=always
RestartSec=5

# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNPROC=infinity
LimitCORE=infinity

# Comment TasksMax if your systemd version does not supports it.
# Only systemd 226 and above support this version.
TasksMax=infinity
OOMScoreAdjust=-999

[Install]
WantedBy=multi-user.target
EOF

modprobe overlay

modprobe: FATAL: Module overlay not found.

lsmod | grep overlay
重新编译内核支持overlay

systemctl daemon-reload
systemctl enable --now containerd
systemctl status containerd

验证安装

ctr version
Client:
  Version:  v1.7.1
  Revision: 1677a17964311325ed1c31e2c0a3589ce6d5c30d
  Go version: go1.20.4

Server:
  Version:  v1.7.1
  Revision: 1677a17964311325ed1c31e2c0a3589ce6d5c30d
  UUID: 0a65fe08-25a6-4bda-a66f-c6f52e334e70

安装runc

安装runc

以下步骤所有节点都执行。

准备文件

wget https://github.com//opencontainers/runc/releases/download/v1.1.7/runc.amd64
chmod +x runc.amd64

查找containerd安装时已安装的runc所在的位置,如果不存在runc文件,则直接进行下一步
which runc
/usr/bin/runc
替换上一步的结果文件

cp  runc.amd64 /usr/bin/runc

验证runc安装

runc -v
runc version 1.1.7
commit: v1.1.7-0-g860f061b
spec: 1.0.2-dev
go: go1.20.3
libseccomp: 2.5.4

安装CNI插件

安装CNI插件

下载地址:https://github.com/containernetworking/plugins/releases

wget https://github.com/containernetworking/plugins/releases/download/v1.3.0/cni-plugins-linux-amd64-v1.3.0.tgz
mkdir -p /opt/cni/bin
tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v1.3.0.tgz

安装crictl

安装 kubernetes 社区提供的 containerd 客户端工具 crictl
根据 https://www.downloadkubernetes.com/ 确定即将安装的Kubernetes版本, 本次即将安装 Kubernetes v1.28.0。 客户端工具 crictl 的版本号需和即将安装的 Kubernetes 版本号一致。
crictl 命令基本和docker一样的用法
下载地址:https://github.com/kubernetes-sigs/cri-tools/blob/master/docs/crictl.md

#wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.27.1/crictl-v1.27.1-linux-amd64.tar.gz
wget https://github.com/kubernetes-sigs/cri-tools/releases/download/v1.28.0/crictl-v1.28.0-linux-amd64.tar.gz
#tar -xf crictl-v1.27.1-linux-amd64.tar.gz -C /usr/local/bin
tar -xf crictl-v1.28.0-linux-amd64.tar.gz -C /usr/local/bin

# 编辑配置文件
cat >  /etc/crictl.yaml << EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 30
debug: false
pull-image-on-create: false
EOF

systemctl daemon-reload && systemctl restart containerd && systemctl status containerd

crictl --version
crictl version v1.28.0

配置Containerd运行时镜像加速器

Containerd通过在启动时指定一个配置文件夹,使后续所有镜像仓库相关的配置都可以在里面热加载,无需重启Containerd。
在/etc/containerd/config.toml配置文件中插入如下config_path:

config_path = "/etc/containerd/certs.d"

说明
/etc/containerd/config.toml非默认路径,您可以根据实际使用情况进行调整。

若已有plugins."io.containerd.grpc.v1.cri".registry,则在下面添加一行,注意要有Indent。若没有,则可以在任意地方写入。

[plugins."io.containerd.grpc.v1.cri".registry]
  config_path = "/etc/containerd/certs.d"

之后需要检查配置文件中是否有原有mirror相关的配置,如下:

[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
    endpoint = ["https://registry-1.docker.io"]

若有原有mirror相关的配置,则需要清理。
执行systemctl restart containerd重启Containerd。
若启动失败,执行journalctl -u containerd检查为何失败,通常是配置文件仍有冲突导致,您可以依据报错做相应调整。
在步骤一中指定的config_path路径中创建docker.io/hosts.toml文件。
在文件中写入如下配置。

mkdir /etc/containerd/certs.d/docker.io -pv
cat > /etc/containerd/certs.d/docker.io/hosts.toml << EOF
server = "https://docker.io"
[host."https://xxx.mirror.aliyuncs.com"]
  capabilities = ["pull", "resolve"]
EOF

systemctl restart containerd

ctr和crictl

ctr是由containerd提供的一个客户端工具。
crictl是CRI兼容的容器运行时命令接口,和containerd无关,由kubernetes提供,可以使用它来检查和调试k8s节点上的容器运行时和应用程序。

crictl pull docker.io/library/nginx
crictl images
crictl rmi docker.io/library/nginx

ctr image pull docker.io/library/nginx:alpine
ctr image ls
ctr image check
ctr image tag docker.io/library/nginx:alpine harbor.k8s.local/course/nginx:alpine
ctr container create docker.io/library/nginx:alpine nginx
ctr container ls
ctr container info nginx
ctr container rm nginx

Posted in 安装k8s/kubernetes.

Tagged with , , , , , .


k8s_安装2_基础准备

二、k8s 集群搭建基础准备

k8s安装方式

Kubeadm,二进制包,minikube,k3s,k3d,kind,MicroK8s等等

minikube

master和worker在一起,测试用
采用生成虚拟机的方法,该虚拟机本质上是一个单节点 K8s 集群

k3s

适合单机测试脚本安装
curl -sfL https://get.k3s.io | sh –

k3d

顾名思义就是 docker 上的 k3s,轻松地在 docker 容器中运行高度可用的轻量级 k3s 集群

MicroK8s

适合离线开发、原型开发和测试,适合开发 IoT 应用,通过 MicroK8s 部署应用到小型Linux设备上。

kind

kind 即 Kubernetes In Docker,顾名思义,就是将 k8s 所需要的所有组件,全部部署在一个docker容器中,是一套开箱即用的 k8s 环境搭建方案。使用 kind 搭建的集群无法在生产中使用,但是如果你只是想在本地简单的玩玩 k8s,不想占用太多的资源,那么使用 kind 是你不错的选择。

Kubeadm 方式

Kubeadm 是 k8s 的部署工具,它提供了 kubeadm init 和 kubeadm join,专用于快速部署 k8s 集群,它能通过两条指令完成一个 Kubenetes 集群的搭建。Kubeadm 部署方式的优点是降低了部署门槛,部署方式快捷且简单;但缺点是屏蔽了诸多细节,遇到问题难以排查是哪里出现了问题。

二进制包安装

过于繁琐
后面会单独配制

k8s测试环境规划

192.168.244.6 harbor.k8s.local #harbor 访问地址
192.168.244.6 repo.k8s.local #harbor
192.168.244.5 node01.k8s.local
192.168.244.7 node02.k8s.local
192.168.244.4 master01.k8s.local

确保每个节点上 MAC 地址和 product_uuid 的唯一性
你可以使用命令 ip link 或 ifconfig -a 来获取网络接口的 MAC 地址
可以使用 sudo cat /sys/class/dmi/id/product_uuid 命令对 product_uuid 校验
生成uuid可以使用uuidgen命令,或者cat一下这个节点获取:/proc/sys/kernel/random/uuid

一、基础环境配置(所有主机均要配置)

第一步:关闭防火墙

#临时关闭
systemctl stop firewalld
systemctl stop iptables
/etc/init.d/iptables stop

#永久关闭
systemctl disable firewalld
systemctl disable iptables
chkconfig iptables off

machine-id修改

在master节点和node节点都需要执行,主要是为了清除克隆机器machine-id值一样的问题
rm -f /etc/machine-id && systemd-machine-id-setup

第二步:关闭 selinux

#永久关闭
setenforce 0 && sed -i '/SELINUX/s/enforcing/disabled/' /etc/selinux/config
#临时关闭
setenforce 0

第三步:关闭 swap

交换分区的配置。kubelet 的默认行为是在节点上检测到交换内存时无法启动。 kubelet 自 v1.22 起已开始支持交换分区。自 v1.28 起,仅针对 cgroup v2 支持交换分区; kubelet 的 NodeSwap 特性门控处于 Beta 阶段,但默认被禁用。
如果 kubelet 未被正确配置使用交换分区,则你必须禁用交换分区。 例如,sudo swapoff -a 将暂时禁用交换分区。要使此更改在重启后保持不变,请确保在如 /etc/fstab、systemd.swap 等配置文件中禁用交换分区,具体取决于你的系统如何配置。

#临时关闭
swapoff -a
#永久关闭
swapoff -a && sed -ri 's/.*swap.*/#&/' /etc/fstab

第四步:配置 ssh 互信

# 直接一直回车就行
dnf install ssh-keygen ssh-copy-id

## 使用rsa加密,兼容低版本
ssh-keygen -t rsa -b 4096 -C "[email protected]"
## 使用ed25519+sha256加密,向后兼容更佳
ssh-keygen -t ed25519 -C 'support OpenSSH 6.5~'
## 默认方式,看系统
ssh-keygen

ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]
ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]
ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]

ssh-copy-id -i ~/.ssh/id_ed25519 [email protected]

#for i in 192.168.244.4 192.168.244.7 ; do ssh-copy-id $i; done

第五步:hosts文件和yum源

设置主机名称,使用命令 hostnamectl set-hostname 主机名

如果不支持DNS解析,在各个节点中添加 hosts,即节点 IP地址+节点名称;

cat >> /etc/hosts << EOF
192.168.244.6 repo.k8s.local
192.168.244.5 node01.k8s.local
192.168.244.7 node02.k8s.local
192.168.244.4 master01.k8s.local
EOF

cat >> /etc/hosts << EOF
192.168.68.1 yjs-prd-master01.k8s.sys.ba.sh
192.168.68.2 yjs-prd-node01.k8s.sys.ba.sh
192.168.68.3 yjs-prd-node02.k8s.sys.ba.sh
EOF

配置完后可以在各台主机上通过ping master/ping node1/ping node2 来测试是否可以ping通

批量配置集群内各主机的hosts

for i in {192.168.244.4,192.168.244.7};do scp /etc/hosts root@$i:/etc/;done

批量配置集群内各主机的静态主机名

#跳过前2行localhost
tail -n +3 /etc/hosts | while read hang;do server=`echo ${hang} | awk -F " " '{print $1}'` && name=`echo ${hang} | awk -F " " '{print $2}'` && echo  ${name} ;done
tail -n +3 /etc/hosts | while read hang;do server=`echo ${hang} | awk -F " " '{print $1}'` && name=`echo ${hang} | awk -F " " '{print $2}'` && ssh -n root@${server} "hostnamectl set-hostname ${name}";done

原文链接:https://blog.csdn.net/UsamaBinLaden6976498/article/details/132897456

酌情关闭集群内主机的 SElinux、 swap、 OS 防火墙,并检查其状态

for i in {192.168.244.5,192.168.244.6}; do ssh root@$i "echo -e ' ';echo -e 'ip: '; \
ip a | grep -E -w 'inet.*ens33';echo -e ' ';echo -e 'SELinux:';sestatus;echo -e ' \
';echo -e 'firewall:'systemctl status firewalld;echo -e ' ';echo -e \
'SWAP: ';swapon --show;echo -e ' '" ; done

替换源

#阿里云
cp -r /etc/yum.repos.d/ /etc/yum.repos.d_bak​
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
    -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.aliyun.com/rockylinux|g' \
    -i.bak \
    /etc/yum.repos.d/rocky-*.repo

#上海交通大学
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
    -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.sjtug.sjtu.edu.cn/rocky|g' \
    -i.bak \
    /etc/yum.repos.d/[Rr]ocky*.repo

#epel源
dnf config-manager --set-enabled crb
dnf install epel-release -y
# 安装 EPEL Repo
#dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
# 安装 EPEL Next Repo
#dnf install -y  https://dl.fedoraproject.org/pub/epel/epel-next-release-latest-9.noarch.rpm
sed -e 's|^metalink=|#metalink=|g' \
    -e 's|^#baseurl=https://download.example/pub|baseurl=https://mirrors.aliyun.com|g' \
    -i.bak \
    /etc/yum.repos.d/epel*.repo
# 注意:
# Rocky Linux 中 #baseurl=https://download.example/pub
# 与 CentOS 相同,而 Alma Linux #baseurl=https://download.fedoraproject.org/pub

dnf makecache

第六步:时间同步,让各个节点(虚拟机)中的时间与本机时间保持一致。

默认集群可接受节点时间差为10s以内

yum install -y chrony
systemctl start chronyd
systemctl enable chronyd
date

### 配制内部ntp服务器
cat > /etc/chrony.conf << EOF 
pool ntp.aliyun.com iburst
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
keyfile /etc/chrony.keys
logdir /var/log/chrony
EOF
systemctl restart chronyd

#使用客户端进行验证
chronyc sources -v

第七步:内核升级(可选)

当前版本centos7.9
uname -a

Linux node01.k8s.local 3.10.0-1160.71.1.el7.x86_64 #1 SMP Tue Jun 28 15:37:28 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

CentOS 7 上安装最新版本 kernel-ml 内核的过程:
不指定版本默认就是当前最新版本
关于内核种类:
kernel-ml——kernel-ml 中的ml是英文【 mainline stable 】的缩写,elrepo-kernel中罗列出来的是最新的稳定主线版本
kernel-lt——kernel-lt 中的lt是英文【 long term support 】的缩写,elrepo-kernel中罗列出来的长期支持版本。ML 与 LT 两种内核类型版本可以共存,但每种类型内核只能存在一个版本。

rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
#导入 elrepo 源的 GPG 公钥,用于验证软件包的签名。
yum install wget

#rhel7
wget http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm
#rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-2.el7.elrepo.noarch.rpm

#rhel8
wget https://www.elrepo.org/elrepo-release-8.el8.elrepo.noarch.rpm

#rhel9
wget https://www.elrepo.org/elrepo-release-9.el9.elrepo.noarch.rpm

#安装 elrepo 源的 rpm 包,添加 elrepo 源。
rpm -Uvh elrepo-release-7.0-2.el7.elrepo.noarch.rpm

rpm -Uvh elrepo-release-8.el8.elrepo.noarch.rpm

rpm -Uvh elrepo-release-9.el9.elrepo.noarch.rpm

#查看现在elrepo里有什么版本的新内核可以用,运行
yum --disablerepo="*" --enablerepo="elrepo-kernel" list available

# 安装 最新版ML 版本
yum --enablerepo=elrepo-kernel install kernel-ml-devel kernel-ml -y
# 安装 最新版LT 版本
yum --enablerepo=elrepo-kernel install kernel-lt-devel kernel-lt -y

#如果要在本机做开发编译,还要安装内核header
yum --enablerepo=elrepo-kernel install kernel-ml-headers -y

#如果提示kernel-ml-headers与旧版本的kernel-header冲突,先把旧版本header删除
yum remove kernel-headers

卸载旧header如提示有依赖旧header的软件包,拷贝列表,先确认关联删除,在安装kernel-ml-headers后再重装这些包

#确认已安装内核版本
rpm -qa | grep kernel

设置开机从新内核启动

CentOS 6.x,比较简单:
修改grub配置文件/etc/grub.conf,改
default=1

default=0

sed -i s/saved/0/g /etc/default/grub

CentOS 7.x,复杂些:
先查看机器上安装的内核启动顺序
awk -F\’ ‘$1=="menuentry " {print i++ " : " $2}’ /etc/grub2.cfg
再把新内核的顺序号(一般是0号)设为默认启动
grub2-set-default 0

Rocky9
设置开机从新内核启动

grub2-editenv list
grub2-set-default 0
grub2-editenv list

最后使grub的新配置生效
cp /boot/grub2/grub.cfg /boot/grub2/grub.bak.cfg

grub2-mkconfig -o /boot/grub2/grub.cfg

Generating grub configuration file ...
Found linux image: /boot/vmlinuz-6.5.6-1.el7.elrepo.x86_64
Found initrd image: /boot/initramfs-6.5.6-1.el7.elrepo.x86_64.img
Found linux image: /boot/vmlinuz-3.10.0-1160.71.1.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-1160.71.1.el7.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-342c8e733f0b488ca5712e22fa426d55
Found initrd image: /boot/initramfs-0-rescue-342c8e733f0b488ca5712e22fa426d55.img
done

更新 grub 配置。

reboot
重启系统,以使用新的内核启动。

总结:
该命令的作用是添加 elrepo 源、安装最新的 kernel-ml 内核包,并更新 grub 引导来使用该内核,从而升级系统的 Linux 内核。

uname -a

Linux master01.k8s.local 6.5.6-1.el7.elrepo.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Oct  6 16:06:35 EDT 2023 x86_64 x86_64 x86_64 GNU/Linux

3.10版本内核 在打开net.ipv4.tcp_tw_recycle 参数时会偶有丢包,4.12 内核已经废弃此选项。

echo 0 > /proc/sys/net/ipv4/tcp_tw_recycle

vim /etc/sysctl.conf

net.ipv4.tcp_tw_recycle = 0

https://blog.csdn.net/a8138/article/details/128939738

第八步:将桥接的 IPv4 流量传递到 iptables 的链(所有节点都设置);优化内核

优化参考:https://blog.csdn.net/ver_mouth__/article/details/126120802
https://help.aliyun.com/zh/ecs/support/common-kernel-network-parameters-of-ecs-linux-instances-and-faq
后继设置的需重启一下系统,否则已启动的进程还是老的参数

#设置

cat > /etc/sysctl.d/k8s.conf << EOF
net.ipv4.tcp_keepalive_time=600
net.ipv4.tcp_keepalive_intvl=30
net.ipv4.tcp_keepalive_probes=10
net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.default.disable_ipv6=1
net.ipv6.conf.lo.disable_ipv6=1
net.ipv4.neigh.default.gc_stale_time=120
net.ipv4.conf.all.rp_filter=0 
net.ipv4.conf.default.rp_filter=0
net.ipv4.conf.default.arp_announce=2
net.ipv4.conf.lo.arp_announce=2
net.ipv4.conf.all.arp_announce=2
net.ipv4.ip_local_port_range= 32768 60999
net.ipv4.ip_forward=1
net.ipv4.tcp_tw_recycle=0
net.ipv4.tcp_tw_reuse=0
net.ipv4.tcp_max_tw_buckets=6000
net.ipv4.tcp_syncookies=1
net.ipv4.tcp_synack_retries=2
net.bridge.bridge-nf-call-ip6tables=1
net.bridge.bridge-nf-call-iptables=1
net.netfilter.nf_conntrack_max=2310720
#net.netfilter.nf_conntrack_tcp_timeout_established=300
#net.netfilter.nf_conntrack_buckets=655360
net.ipv4.neigh.default.gc_thresh1=1024
net.ipv4.neigh.default.gc_thresh2=4096
net.ipv4.neigh.default.gc_thresh3=8192
net.ipv6.neigh.default.gc_thresh1=8192
net.ipv6.neigh.default.gc_thresh2=32768
net.ipv6.neigh.default.gc_thresh3=65536
net.core.netdev_max_backlog=16384

net.core.rmem_max = 16777216 
net.core.wmem_max = 16777216
net.ipv4.tcp_max_syn_backlog = 8096 
net.core.somaxconn = 32768 
fs.inotify.max_user_instances=8192 
fs.inotify.max_user_watches=524288 
fs.file-max=52706963
fs.nr_open=52706963
kernel.pid_max = 4194303
net.bridge.bridge-nf-call-arptables=1
vm.swappiness=0 
vm.overcommit_memory=1 
vm.panic_on_oom=0 
vm.max_map_count = 262144
EOF

说明

net.ipv4.tcp_tw_recycle =0 #3.10版本内核 在打开net.ipv4.tcp_tw_recycle 参数时会偶有丢包,4.12 内核已经废弃此选项。
net.ipv4.tcp_tw_reuse =0 #导致Pod健康检查异常

net.ipv4.tcp_keepalive_time=600 #此参数表示TCP发送keepalive探测消息的间隔时间(秒)
net.ipv4.tcp_keepalive_intvl=30 #tcp检查间隔时间(keepalive探测包的发送间隔)
net.ipv4.tcp_keepalive_probes=10  #tcp检查次数(如果对方不予应答,探测包的发送次数)
net.ipv6.conf.all.disable_ipv6=1 #禁用IPv6,修为0为启用IPv6
net.ipv6.conf.default.disable_ipv6=1 #禁用IPv6,修为0为启用IPv6
net.ipv6.conf.lo.disable_ipv6=1 #禁用IPv6,修为0为启用IPv6
net.ipv4.neigh.default.gc_stale_time=120 #ARP缓存条目超时
net.ipv4.conf.all.rp_filter=0  #默认为1,系统会严格校验数据包的反向路径,可能导致丢包
net.ipv4.conf.default.rp_filter=0 #不开启源地址校验
net.ipv4.conf.default.arp_announce=2 #始终使用与目的IP地址对应的最佳本地IP地址作为ARP请求的源IP地址
net.ipv4.conf.lo.arp_announce=2 #始终使用与目的IP地址对应的最佳本地IP地址作为ARP请求的源IP地址
net.ipv4.conf.all.arp_announce=2 #始终使用与目的IP地址对应的最佳本地IP地址作为ARP请求的源IP地址
net.ipv4.ip_local_port_range= 45001 65000 # 定义网络连接可用作其源(本地)端口的最小和最大端口的限制,同时适用于TCP和UDP连接。阿里用 32768 60999
net.ipv4.ip_forward=1 # 其值为0,说明禁止进行IP转发;如果是1,则说明IP转发功能已经打开。
net.ipv4.tcp_max_tw_buckets=6000 #配置服务器 TIME_WAIT 数量
net.ipv4.tcp_syncookies=1 #此参数应该设置为1,防止SYN Flood
net.ipv4.tcp_synack_retries=2 #表示回应第二个握手包(SYN+ACK包)给客户端IP后,如果收不到第三次握手包(ACK包),进行重试的次数(默认为5)
net.bridge.bridge-nf-call-ip6tables=1 # 是否在ip6tables链中过滤IPv6包
net.bridge.bridge-nf-call-iptables=1 # 二层的网桥在转发包时也会被iptables的FORWARD规则所过滤,这样有时会出现L3层的iptables rules去过滤L2的帧的问题
net.netfilter.nf_conntrack_max=2310720 #连接跟踪表的大小,建议根据内存计算该值CONNTRACK_MAX = RAMSIZE (in bytes) / 16384 / (x / 32),并满足nf_conntrack_max=4*nf_conntrack_buckets,默认262144
#net.netfilter.nf_conntrack_tcp_timeout_established=300
#net.netfilter.nf_conntrack_buckets=655360 # 哈希表大小(只读)(64位系统、8G内存默认 65536,16G翻倍,如此类推)

net.ipv6.neigh.default.gc_thresh1=8192
net.ipv6.neigh.default.gc_thresh2=32768
net.ipv6.neigh.default.gc_thresh3=65536

#gc_thresh3 是ARP回收表大小的绝对限制
#gc_thresh2 设置为等于系统的最大预期邻居条目数的值
#在这种情况下,gc_thresh3 应该设置为一个比 gc_thresh2 值高的值,例如,比 gc_thresh2 高 25%-50%,将其视为浪涌容量。
#gc_thresh1 提高到较大的值;此设置的作用是,如果表包含的条目少于 gc_thresh1,内核将永远不会删除(超时)过时的条目。

net.core.netdev_max_backlog=16384 # 每CPU网络设备积压队列长度
net.core.rmem_max = 16777216 # 所有协议类型读写的缓存区大小
net.core.wmem_max = 16777216 # 最大的TCP数据发送窗口大小
net.ipv4.tcp_max_syn_backlog = 8096 # 第一个积压队列长度
net.core.somaxconn = 32768 # 第二个积压队列长度
fs.inotify.max_user_instances=8192 # 表示每一个real user ID可创建的inotify instatnces的数量上限,默认128.
fs.inotify.max_user_watches=524288 # 同一用户同时可以添加的watch数目,默认8192。
fs.file-max=52706963 # 文件描述符的最大值
fs.nr_open=52706963 #设置最大微博号打开数
kernel.pid_max = 4194303 #最大进程数
net.bridge.bridge-nf-call-arptables=1 #是否在arptables的FORWARD中过滤网桥的ARP包
vm.swappiness=0 # 禁止使用 swap 空间,只有当系统 OOM 时才允许使用它
vm.overcommit_memory=1 # 不检查物理内存是否够用
vm.panic_on_oom=0 # 开启 OOM
vm.max_map_count = 262144
#使其生效
sysctl -p
sysctl --system
sysctl -a|grep vm.max_map_count

#确保每台机器的uuid不一致,如果是克隆机器,修改网卡配置文件删除uuid那一行
cat /sys/class/dmi/id/product_uuid

#加载网桥过滤模块,没有会影响node中pod和pod通信
modprobe br_netfilter

#centos6下报错
error: "net.bridge.bridge-nf-call-arptables" is an unknown key
error: "net.bridge.bridge-nf-call-iptables" is an unknown key
error: "net.bridge.bridge-nf-call-ip6tables" is an unknown key
modprobe bridge

# 查看网桥过滤模块是否加载成功
lsmod | grep br_netfilter

#启动加载
cat > /etc/sysconfig/modules/br_netfilter.modules << EOF
#centos6 modprobe bridge
modprobe bridge
modprobe br_netfilter
EOF
chmod 755 /etc/sysconfig/modules/br_netfilter.modules

rocky9

echo 'br_netfilter' >> /etc/modules-load.d/br_netfilter.conf
cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF

参考
https://imroc.cc/kubernetes/trick/deploy/set-sysctl/
https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/

# 宿主ulimit
cat /etc/security/limits.conf

cat > /etc/security/limits.d/20-nofile.conf <<EOF
root soft nofile 65535
root hard nofile 65535
* soft nofile 65535
* hard nofile 65535
EOF

cat > /etc/security/limits.d/20-nproc.conf <<EOF
*    -     nproc   65535
root soft  nproc  unlimited
root hard  nproc  unlimited
EOF

echo "ulimit -HSn 65535" >> /etc/rc.local

ulimit -a 
sysctl -p

systemctl show sshd

# containerd.service
安装containerd后替换
sed -i 's/LimitNOFILE=infinity/LimitNOFILE=65535/' /usr/lib/systemd/system/containerd.service
systemctl daemon-reload
systemctl restart containerd

# centos7 system.conf
## 替换
#sed -n 's/#DefaultLimitNOFILE=/DefaultLimitNOFILE=65335/p' /etc/systemd/system.conf
#sed -i 's/^#DefaultLimitNOFILE=/DefaultLimitNOFILE=65335/' /etc/systemd/system.conf
#rocky9
sed -n 's/#DefaultLimitNOFILE=1024/DefaultLimitNOFILE=65335/p' /etc/systemd/system.conf
sed -i 's/^#DefaultLimitNOFILE=1024/DefaultLimitNOFILE=65335/' /etc/systemd/system.conf

##手动编辑
vi /etc/systemd/system.conf
DefaultLimitNOFILE=65335

cat /etc/systemd/system.conf|grep DefaultLimitNOFILE

systemctl daemon-reexec

openssl升级

建议openssl升级到1.1.1或更高版本
centos6.10
openssl version

OpenSSL 1.0.1e-fips 11 Feb 2013

centos7
openssl version

OpenSSL 1.0.2k-fips  26 Jan 2017
2023-Sep-11 14:46:17    openssl-1.1.1w.tar.gz 
wget --no-check-certificate https://www.openssl.org/source/openssl-1.1.1w.tar.gz
tar zxvf openssl-1.1.1w.tar.gz
cd openssl-1.1.1w
./config --prefix=/usr/local/openssl --shared
make -j 8 && make install

echo "/usr/local/openssl/lib" >> /etc/ld.so.conf
ldconfig -v
ldd /usr/local/openssl/bin/openssl 

mv /usr/bin/openssl /usr/bin/openssl.old
ln -sv /usr/local/openssl/bin/openssl /usr/bin/openssl
openssl version
OpenSSL 1.1.1w  11 Sep 2023

第八步:配置ipvs功能(可选)

在kubernetes中service有两种代理模型,一种是基于iptables的,一种是基于ipvs的,两者比较的话,ipvs的性能明显要高一些,但是如果要使用它,需要手动载入ipvs模块。
所有节点配置ipvs模块,在内核4.19+版本nf_conntrack_ipv4已经改为nf_conntrack, 4.18以下使用nf_conntrack_ipv4即可
在 3.10 内核版本中从iptables 改用ipvs,kube-proxy 会报如下错误

E0415 09:46:55.397466       1 proxier.go:1192] Failed to sync endpoint for service: 172.16.0.82:30080/TCP, err: parseIP Error ip=[172 16 100 7 0 0 0 0 0 0 0 0 0 0 0 0]
E0415 09:46:55.398639       1 proxier.go:1950] Failed to list IPVS destinations, error: parseIP Error ip=[172 16 100 7 0 0 0 0 0 0 0 0 0 0 0 0]

可能会出现以下问题:
ipvs 指向的后端节点不对,如果重新 svc 删除重建又是对的
当副本数量变动时,ipvs 不能立马感知到
如果直接用域名访问 svc 时,会出现解析不了的情况

如使用ipvs建议先升级系统内核

Calico 在做网络策略限制的时候要求 kubec-proxy 组件不能采用 –masquerade-all 启动

所有工作节点上均执行

# 安装ipset和ipvsadm
yum install ipset ipvsadmin ipvsadm sysstat conntrack libseccomp -y
#  添加需要加载的模块写入脚本文件 
cat > /etc/sysconfig/modules/ipvs.modules << EOF
#!/bin/bash 
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack
#modprobe -- nf_conntrack_ipv4
EOF
# 为脚本文件添加执行权限
chmod +x /etc/sysconfig/modules/ipvs.modules
# 执行脚本文件
sh /etc/sysconfig/modules/ipvs.modules

# rocky9 安装ipset和ipvsadm
dnf install ipset ipvsadm

modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack

cat >> /etc/modules-load.d/ipvs.conf <<EOF 
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
ip_tables
ip_set
xt_set
ipt_set
ipt_rpfilter
ipt_REJECT
ipip
EOF

systemctl restart systemd-modules-load.service

# 查看对应的模块是否加载成功
lsmod | grep -e ip_vs -e nf_conntrack
lsmod | grep -e bridge

第九步: 添加指定id的用户和用户组

cat /etc/passwd
cat /etc/group

/usr/sbin/groupadd k8s -g 1000
/usr/sbin/useradd -g k8s k8s -s /sbin/nologin -u 1000
id k8s

/usr/sbin/groupadd website -g 500

/usr/sbin/useradd -g website www -s /sbin/nologin -u 500
#/usr/sbin/useradd -g website www -d /dev/null -s /sbin/nologin -u 500

mkdir /home/www
chown www:website -R /home/www
chmod 700 /home/www
usermod -d /home/www www

第十步:工具安装

修改各节点默认挂载为Soft方式,防止nfs异常后卡死
手动编辑
vi /etc/nfsmount.conf

Soft=True

替换

echo 'Soft=True' >> /etc/nfsmount.conf

yum install sysstat -y

安装常用工具

yum -y install wget vim net-tools nfs-utils telnet yum-utils device-mapper-persistent-data lvm2 tar curl lrzsz rsync psmisc sysstat lsof

创建宿主共享目录,filebeat,ingress,nginx,php

mkdir -p /localdata/{es,filebeat,log}
mkdir -p /localdata/es/data
mkdir -p /localdata/filebeat/{data,socket}
mkdir -p /localdata/log/{ext-ingress,int-ingress,nginx,php}
chmod -R 777 /localdata/

第十一步:重启服务器

查看以上所有配置是否生效
三台主机上均执行

systemctl status firewalld # 查看防火墙
getenforce   # 查看selinux
lsmod | grep br_netfilter    # 查看网桥过滤模块
lsmod | grep -e ip_vs -e nf_conntrack  # 查看 ipvs 模块
sysctl net.bridge.bridge-nf-call-iptables

如果都正确,表示三台主机环境初始化均成功

最后重启一下
reboot

Posted in 安装k8s/kubernetes.

Tagged with , .


k8s_安装1_规划

参考:
https://zhuanlan.zhihu.com/p/646927705
https://blog.csdn.net/qq_37419449/article/details/122157277
https://blog.csdn.net/Gong_yz/article/details/12948302

centos7.9内核选择

可以选择长期支持版kernel-lt或最新版内核kernel-ml
推荐升级到最新内核

这里升级3.10 -> 6.5.6-1.el7.elrepo.x86_64

4.0以下内核存在cgroup泄漏问题,长时间运行后无法新建pod.
5.9以下内核使用ipvs会有1S延迟.

内核是3.10.x的docker默认使用文件系统是overlay1,overlay1最多使用64层,overlay2可以使用128层,升级至4.x之后的内核就默认使用overlay2,同时也修复了cgroup的问题。

要使用完整的 Cilium 功能, 需要非常新版本的 Linux 内核. 目前官方推荐的 Linux Kernel 是 ≥ 5.10

cgroups v2自Linux内核4.5版本加入支持,但到5.8才设置为默认.RHEL/Rocky 9 默认内核为5.14,默认为v2版本。

  • Linux各发行版将cgroups v2作为默认的情况如下:
  • Container-Optimized OS(从 M97 开始)
  • Ubuntu(从 21.10 开始,推荐 22.04+)
  • Debian GNU/Linux(从 Debian 11 Bullseye 开始)
  • Fedora(从 31 开始)
  • Arch Linux(从 2021 年 4 月开始)
  • RHEL 和类似 RHEL 的发行版(从 9 开始)

查看cgroups版本及默认版本

cgroup v2可以支持容器级别的(但还没有实现)OOM而非某个进程。一个容器或Pod可以运行多个进程,以前OOM killer不考虑它们的整体性,只杀死其中的一些进程,这种方式可能导致Pod进入不一致的状态。cgroup v2接口允许我们判断特定cgroup中的进程是否相互依赖,从而确定是否应该同时关闭。

另一个使用场景是可以加强集群安全性。管理没有root权限的容器的技术称为rootless容器,其允许由受限用户运行Kubernetes节点组件(如kubelet),提高安全性,并允许非管理用户在共享机器上创建Kubernetes集群等。

最后,eBPF需要cgroup v2来启用它的所有功能,当前Cilium是一个依托eBPF技术实现cni插件的开源项目,它的一些功能需要使用cgroup v2,当启用cgroup v2时,可以替换kube-proxy。

cgroups v1

grep cgroup /proc/filesystems
nodev   cgroup
stat -fc %T /sys/fs/cgroup/
tmpfs       # tmpfs,说明默认为 cgroups v1

支持cgroup2,但默认为cgroupsv1

grep cgroup /proc/filesystems
nodev   cgroup
nodev   cgroup2
stat -fc %T /sys/fs/cgroup/
tmpfs       # tmpfs,说明默认为 cgroups v1

默认为cgroupsv2

stat -fc %T /sys/fs/cgroup/
cgroup2fs      # cgroup2fs,说明默认为 cgroups v2

Kubernetes版本选择

Kubernetes每年出一个大版本,只维护最近的三个大版本,升级不能跨多版本,需一级一级升。
官方建议每年升一次级
这里使用1.28.6

Kubernetes 安装方式

推荐使用kubeadm
单独安装需要操作二十几个证书文件,比较麻烦.
kubeadm默认根证书有效期10年,认证通信证书为1年,需重新编译kubeadm延长时间。
cluster_name不要使用域名

Kubernetes TLS 认证通信

etcd是否独立

节点大于 25 时单独布署
线上最低可以融合部署3个

k8s代理模式选择

推荐ipvs
ipvs/iptables 在集群中不超过1000个服务的时候,iptables 和 ipvs 并无太大的差别,在有5千个服务(4万条规则)时,添加一条规则耗时11分钟
https://cloud.tencent.com/developer/article/1470033?from=15425

CNI接口选择

flannel/calico/cilium

小型集群推荐flannel -> vxlan+Directrouting //直接路由,跨网段使用vxlan,同网段使用host-gw模式。
线上推荐Calico

flannel,不支持pod之间的网络隔离.更像是经典的桥接模式的扩展,容器与容器之间,主机与容器之间都能互相通信
vxlan/hostgw

calico 适用场景:k8s环境中的pod之间需要隔离,Calico 不使用隧道或 NAT 来实现转发,通过 host 上路由配置完成跨 Host 转发

Cilium 性能出色,但是比较复杂

主机名命名规划

c1g-test-master01.k8s.sys.sh

ip分配

node节点:192.168.68.0/24
pod网段:10.128.0.0/16 默认:10.244.0.0/16
service网段(集群网段):10.96.0.0/16 默认:10.96.0.0/12
service集群网段:10.96.0.0/10

阿里云Terway
vpc 192.168.128.0/20
Service CIDR:172.16.0.0/20

Terway Pod独占模式专有网络网段 虚拟交换机网段 Pod虚拟交换机网段 Service CIDR网段 最大可分配Pod地址数
192.168.0.0/16 192.168.0.0/19 192.168.32.0/19 172.21.0.0/20 8192

容器选择

docker不再支持centos6
推荐Containerd
Docker/Containerd
Podman/CRI-O
从 Kubernetes 1.20 版本之后,默认推荐使用 Containerd 作为容器运行时,而不再依赖于 Docker。
从 Kubernetes 1.24 开始,删除了对 Docker(Dockershim)的容器运行时接口(CRI)的支持

使用containerd时
管理工具ctr+crictl
nerdctl+buildkit

harbor

建议单独机器,使用docker操作镜像
需要考虑点:

  • Trivy扫描镜像?
  • 高可用?主从复制或共享存储
  • 是否修改端口
  • 是否开启https
  • 仓库命名,使用统一名称/参照官方
  • 项目命名规则,用域名做项目名
  • 用户管理ldap?

存储

不要和harbor放一起,推送大镜像时整个集群会有io压力
测试可用nfs,线上推荐cephfs

ingress选择

通常使用Kubernetes Ingress
更多功能可以推荐APISIX

ingress 运行方式

现用 DaemonSet+HostNetwork+NodePort+nodeSelector

  • Deployment or DaemonSet?
  • HostNetwork 是否开启?
  • NodePort 是否开启?
  • nodeSelector or nodeAffinity?

damonset运行应用

  • ingress
  • NodeLocalDNS
  • filebeat
  • Prometheus

dns

CoreDNS从v1.13 开始替代 kube-dns,Kubernetes 1.21 版本中,kubeadm 移除了对将 kube-dns 作为 DNS 应用的支持,v1.24只支持CoreDNS.
NodeLocal->coredns(集群内域名,自定义指向)->自有dns(业务域名指向)->公网dns.
没有NodeLocal情况下,重启coredns pod导致集群业务解析域名失败5分钟。

Metrics Server

dashboard 需要
弹性伸缩 需要

Helm是否配置

Argocd灰度发布搭配

Ingress Nginx

  • Ingress Nginx
  • Istio
  • Traefik

StatefulSet是否使用

db等需要持久化数据

service 命名

$service_name.$namespace_name.svc.$cluster_name
如有内部调用,确定后不要修改

标签命名

显示默认标签
kubectl get nodes –show-labels

kubectl label node master01.k8s.local role=master
kubectl label node node01.k8s.local role=node

pod运行用户及用户组

www:website
指定uid:gid
500:500

k8s:k8s
1000:1000


KubeSphere

容器平台中维护和管理独立部署的 Kubernetes 集群。
联邦:多个 Kubernetes 集群可以聚合在一起作为 Kubernetes 资源池。当用户部署应用程序时,副本可以部署在资源池中的不同 Kubernetes 集群上。由此,跨区域和多集群实现了高可用性。

Submariner

Submariner 是一个完全开源的项目,可以帮助我们在不同的 Kubernetes 集群之间(无论是在本地还是云端)实现网络通信

Kubernetes的网络通信问题:

  •   1. 容器间通信: 即同一个Pod内多个容器间通信,通常使用loopback来实现。
  •   2. Pod间通信: K8s要求,Pod和Pod之间通信必须使用Pod-IP 直接访问另一个Pod-IP
  •   3. Pod与Service通信: 即PodIP去访问ClusterIP,当然,clusterIP实际上是IPVS 或 iptables规则的+ 虚拟IP,是没有TCP/IP协议栈支持的。但不影响Pod访问它.
  •   4. Service与集群外部Client的通信,即K8s中Pod提供的服务必须能被互联网上的用户所访问到。

Pod 初始化核心流程如下:

  • kube-apiserver 收到客户端请求(Controller 或 kubectl 客户端)后,创建对应的 Pod;
  • kube-scheduler 按照配置的调度策略进行 Pod 调度,选择最为合适的 Node 作为目标节点;
  • kubelet(运行于每个 Node 上的 K8s agent)Watch 监听到调度到所在节点的 Pod(s),开始真正创建 Pod;
  • 由 CRI 首先创建出 PodSandbox,初始化对应的网络 net namespace,调用 CNI 获取 Pod IP;
  • 接着 CRI 开始创建 Pod 中第一个 pause container,绑定到上一步创建的 net namespace 和 Pod IP;
  • 接着由 CRI 依次创建和启动 Pod 中声明的 initContainers 和 containers 容器;
  • 当所有的 containers 运行起来后,探针探测容器运行符合预期后,Pod 状态最终更新为 Running;

关于K8S中端口的概念区分

  • 1、Port:
    是service端口,即k8s中服务之间的访问端口 ,clusterIP:port 是提供给集群内部客户访问service的入口

  • 2、NodePort:
    容器所在node节点的端口,通过nodeport类型的service暴露给集群节点,外部可以访问的端口

  • 3、TargetPort
    是pod的端口 ,从port和nodePort来的流量经过kube-proxy流入到后端pod的targetPort上,最后进入容器。

  • 4、ContainerPort
    是pod内部容器的端口,targetPort映射到containerPort

4种端口作用不一样,port和nodePort都是service的端口。
port暴露给集群内客户访问服务,nodePort暴露给集群外客户访问服务。
这两个端口到来的数据都需要经过反向代理kube-proxy流入后端pod的targetPod,从而到达pod中的容器。

nodeport端口范围

默认情况下,k8s 集群 nodePort 分配的端口范围为:30000-32767,如果我们需要更多的端口,或者重新规划使用端口,需要进行调整.
找到kube-apiserver.yaml文件的绝对路径,其路径为"/etc/kubernetes/manifests/kube-apiserver.yaml",并添加参数"- –service-node-port-range=10000-65535"
systemctl daemon-reload
systemctl restart kubelet

K8s 中多种 IP

Pod IP CIDR

在 K8s 中最常见的 IP 类型就是 Pod IP,在初始化 K8s 集群的时候,通过–cluster-cidr参数控制 Pod IP CIDR 网段,所有 Pod 动态分配的 IP 都会落在此 CIDR 网段内。
具体参数控制如下:通过 kube-controller-manager 组件的–cluster-cidr参数进行配置,根据集群规模一般会选择 16 位的网段来配置集群支持的 Pod IP CIDR 网段,如 10.0.0.0/16,理论上最大支持 2 ^ (32 – 16) = 65536 个 Pod IP 的分配。
【集群规模】可按需配置 Pod IP CIDR,K8s 官方支持的一个大集群(large cluster),最大支持约 5k Nodes、15w Pods。

Node CIDR

在通过 kube-controller-manager 组件的–cluster-cidr控制了 Pod IP 的 CIDR 网段后,首先会在集群中每个 Node 分配一个 subnet CIDR,他们都属于–cluster-cidr网段。
具体参数控制如下:通过 kube-controller-manager 组件的–allocate-node-cidrs=true、–node-cidr-mask-size=24参数控制每个 Node 节点的 subnet CIDR 子网段,这样落在每个 Node 上的 Pod 最大的可分配 IP 数量为 2 ^ (32 – 24) = 256 个,各云厂商会根据自己的网络策略,一般会预留一部分,最终可分配的 IP 一般为最大个数的一半 (128 个)。
【双协议栈】若开启了 dual-stack IP,则可通过–node-cidr-mask-size-ipv4=24、–node-cidr-mask-size-ipv6=64分别控制 IPv4 和 IPv6 的 Node CIDR 子网大小。
在 K8s 标准集群中,通过 kubelet 组件的–max-pods=110控制了默认一个 Node 最大的 Pod 数量为 110 个。

Service IP CIDR

除了上面提到的 Pod IP CIDR 和 Node CIDR 外,K8s 中还有一类 Service IP CIDR,控制 Service 资源的ClusterIP网段范围。
具体参数控制如下:通过 kube-apiserver 和 kube-controller-manager 组件的–service-cluster-ip-range=10.96.0.0/12控制 ServiceClusterIP的网段范围。
根据 Service Type 不同,除了Headless Service显式将.spec.clusterIP=None设置后,生成的 Service 将不会分配 ClusterIP,其他类型的 Service 则都会动态分配 ClusterIP
需要注意的是,Service 动态分配的 ClusterIP 仅在 K8s 集群内部可访问,通过 K8s 内置的 DNS 进行 Service 域名解析到此 ClusterIP,转发到后端真正的 Pod(s) 时进行流量的负载均衡。
【外部访问】若需要从集群外部访问集群内服务,可通过NodePort 或 EXTERNAL-IP 进行访问,还可通过 Ingress 进行更灵活的 L7 (http/https) 流量访问控制。
k8s集群初始化时的service网段,pod网段,网络插件的网段,以及真实服务器的网段,都不能相同,如果相同就会出各种各样奇怪的问题,而且这些问题在集群做好之后是不方便改的,改会导致更多的问题,所以,就在搭建前将其规划好。

Pod IP 分配流程

CNI-IPAM 分配 IP

host-local:是最常见的使用方式,通过在宿主机 Node 上以文件读写的方式,进行 IP 分配与释放。其中 IP 分可配的 range 范围由上面 2.2 所述,通过 Controller 为每一个 Node 分配对应的 CIDR,host-local 插件将从这个 Node CIDR 中动态分配 IP 给 Pod 使用。
其它有dhcp 配置复杂度高,实际使用较少,static 是通过直接指定 IP 地址,为 Pod 分配指定的 IP,支持 IPv4/IPv6,主要用于 debug 或指定 IP 分配的场景,一般较少使用。

hostNetwork 使用 Node IP
Pod 在创建的时候,可以设置 pod.spec.hostNetwork = true/false,表示是否宿主机 Node 的网络,若 hostNetwork = true,则 podIP 就直接设为宿主机 hostIP。

Pod IP 双协议栈
K8s 官方在 v1.20 (v1.23 发布 stable) 版本支持了 IPv4/IPv6 dual-stack 双协议栈

Pod IP 固定与回收
K8s 中通过 StatefulSet 实现有状态服务的管理,其生成的 Pod 编号 (如 mysql-0, mysql-1, mysql-2) 是唯一且重建后不变。某些业务场景下,业务上层需要对应的 Pod IP 保持不变,这样在 Pod 异常后快速拉起,上层业务不需要变更 IP 就可以自动恢复。因此这种场景就需要 Pod IP 在重建前后保持一致。
在 Pod 被删除后,还可以指定 Pod IP 的保留时长,防止短时间新创建的 Pod 复用了最近被删除 Pod 的 IP,很容易给上层业务造成困扰与异常,造成业务的不稳定。因此用户或各大云厂商可通过设计与实现 Pod 的固定与定时回收机制满足有状态服务的固定 IP 需求。

【思路之一】
可设计一个 ReservedIP CRD + 对应的 CNI plugin,在创建 Pod 时记录某个 StatefulSet 下对应 namespace/podName 与 ReservedIP 的映射关系,当此 namespace/podName 删除时,仅仅记录 ReservedIP 的 TTL (如 24h)。
在 TTL 过期之前,再次创建同名的 namespace/podName,则直接用之前保留的 Pod IP。若 TTL 已过期,则由对应的 GC 逻辑去真正调用 CNI IPAM plugin,删除对应的 Pod IP。

规划一个小规模k8s集群

规划200个25节点的k8s集群

每个node 一个c类,254个ip

--node-cidr-mask-size=24
10.128.0.0/24

以Nodes数量在25以内,每个集群64个B类,62个可用,共16002 个ip
默认参数10.244.0.0/16

--cluster-cidr=18
10.128.0.0/18
10.128.64.0/18
10.128.128.0/18
10.128.192.0/18

一个集群,每个node 20个pod算,62*20=1240个pod。
简单点直接使用 –cluster-cidr=16,分配整个B类
10.128.0.0/16

整个k8s,64个C类,估算62*4=248个集群,共4194302个ip
10.128.0.0/10

ip地址网段规划:

node节点:192.168.68.0/24
pod网段:10.128.0.0/16 默认:10.244.0.0/16
service网段(集群网段):10.96.0.0/16 默认:10.96.0.0/12
service集群网段:10.96.0.0/10 
service-cidr 只在Kubernetes集群内使用,不能和PodCIDR及本机网络有重叠或者冲突

节点命名应包含集群名称,节点角色,节点名称,此为固定格式,节点名称仅支持小写,集群名称部署完成后不能修改
c1g-test-master01.k8s.sys.sh
c1g-test-master02.k8s.sys.sh

node02.k8s.local

vip 192.168.68.160
c1g-prd-master01.k8s.sys.sh 192.168.68.1    
c1g-prd-master02.k8s.sys.sh 192.168.68.2    
c1g-prd-master03.k8s.sys.sh 192.168.68.3    
c1g-prd-node01.k8s.sys.sh   192.168.68.4    
c1g-prd-node02.k8s.sys.sh   192.168.68.5    
c1g-prd-node03.k8s.sys.sh   192.168.68.6    

k8s通过CNI接口接入其他插件来实现网络通讯。目前比较流行的插件有flannel,calico等。
CNI插件存放位置:# cat /etc/cni/net.d/10-flannel.conflist

插件使用的解决方案如下:
虚拟网桥,虚拟网卡,多个容器共用一个虚拟网卡进行通信。
多路复用:MacVLAN,多个容器共用一个物理网卡进行通信。
硬件交换:SR-LOV,一个物理网卡可以虚拟出多个接口,这个性能最好。

容器间通信:同一个pod内的多个容器间的通信,通过lo即可实现;

pod之间的通信:
同一节点的pod之间通过cni网桥转发数据包。(brctl show可以查看)
不同节点的pod之间的通信需要网络插件支持。

pod和service通信: 通过iptables或ipvs实现通信,ipvs取代不了iptables,因为ipvs只能做负载均衡,而做不了nat转换。

pod和外网通信:iptables的MASQUERADE。

Service与集群外部客户端的通信;(ingress、nodeport、loadbalancer)

============
https://blog.51cto.com/u_14035463/5585073

一、k8s 集群平台规划

操作系统

CentOS
最低配置 CentOS 7.6 kernel 4.4.x 推荐版本CentOS 7.9

Ubuntu
最低配置 Ubuntu 16.04.5 4.4.0-131 推荐版本Ubuntu 18.04.5 4.15.0

用virtbox 安装centos7.9
操作系统为最小化安装,需yum源和apt源.兼容包,开发工具,管理工具。
2c4g,30G,将显示设置中的“显卡控制器”设置为vboxvga,nat网络

yum install wget  lrzsz net-tools nfs-utils curl curl-devel unzip sudo telnet rsync
yum install chrony
systemctl status chronyd
systemctl restart chronyd
systemctl enable chronyd
/bin/timedatectl set-timezone Asia/Shanghai
/bin/timedatectl set-local-rtc 1

cat >/etc/locale.conf<<EOF
LANG="en_US.UTF-8"
SUPPORTED="zh_CN.UTF-8:zh_CN:zh"
SYSFONT="latarcyrheb-sun16"
EOF

集群架构规划

k8s 集群可以有两种规划方式,单master集群 和 多master集群,也就是一主多从和多主多从

宿主机

系统Centos7.9

单机测试环境

虚拟机和主机之间网络连接方式改为桥接模式,没有IP条件用NAT
一主二从

master:cpu:2 mem:2G hd:30G
node:cpu:2 mem:4G hd:30G及以上

线下测试环境

一主二从

master:cpu:2 mem:4G hd:30G
node:cpu:4 mem:8G hd:40G及以上

线上环境

使用物理机规格推荐
管理节点
CPU Xeon 4214 10 core 2.2GHz(以上) 最低2  推荐2
Memory 16GB ECC DDR4  RDIMM(以上)最低32G  推荐 64G+
Raid 缓存2GB NV 带电容保护,无特别要求、支持raid1  1
HD 600GB SAS 10K企业级硬盘,如etcd 融合部署,可考虑SSD 盘作为数据盘 最低1.2T 推荐2.4T以上
工作节点配置建议
CPU Xeon 4214 10 core 2.2GHz(以上) 最低2  推荐2
Memory 16GB  ECC DDR4 ?RDIMM(以上)最低64G  推荐 128G+
Raid 缓存2GB NV 带电容保护,无特别要求、支持raid1  1
HD 600GB SAS 10K企业级硬盘,如etcd 融合部署,可考虑SSD 盘作为数据盘 最低1.2T 推荐2.4T以上
使用虚拟机规格推荐
管理节点
最小
master:cpu:8 mem:16G hd:300G
推荐
master:cpu:16+ mem:64G+ hd:600G+
工作节点配置建议
node:cpu:8 mem:32G hd:600G
node:cpu:16+ mem:64G+ hd:1.2T+

集群节点命名规划

节点命名应包含集群名称,节点角色,节点名称,此为固定格式,节点名称仅支持小写,集群名称部署完成后不能修改

格式:集群名称 + 节点角色 + 节点名称
示例:
prd-blog-master01.k8s.local

存储

nfs、ceph、gluster
不推荐采用本地存储方式

k8s代理模式

ipvs/iptables
Iptables:

  • 灵活,功能强大
  • 规则遍历匹配和更新,呈线性时延

IPVS:

  • 工作在内核态,有更好的性能
  • 调度算法丰富:rr,wrr,lc,wlc,ip hash…

ipvs依赖iptables进行包过滤、SSNAT、masquared(伪装),如果没有加载并启用ipvs模块,或者没有配置ipvs相关配置,则会被降级成iptables模式。

如何查看k8s中kube-proxy的模式是ipvs还是iptables

kubectl get configmap kube-proxy -n kube-system -o yaml | grep mode
cat /var/log/kube-proxy.log | grep "Using iptables Proxier"

修改模式
kubectl edit configmap kube-proxy -n kube-system
删除节点原kube-proxy的pod,让k8s自己重建

DNS 模式

kubedns/coredns

CoreDNS:是一个DNS服务器,Kubernetes默认采用,以Pod部署在集群中, CoreDNS服务监视Kubernetes API,为每一个Service创建DNS记录用于域名解析。

NodeLocal DNSCache
解决CoreDNS 性能问题有查询产生5s的延时.

网络 CNI 选型

同一个pod内的多个容器可以互相通信,共用网络,通过lo即可实现。
同一节点的pod之间通过cni网桥转发数据包。
不同节点的pod之间的通信需要网络插件支持。
pod和service通信: 通过iptables或ipvs实现通信,ipvs取代不了iptables,因为ipvs只能做负载均衡,而做不了nat转换。
pod和外网通信使用iptables的M地址伪装功能。
Service与集群外部客户端的通信;(ingress、nodeport、loadbalancer)

目前Kubernetes支持多种CNI 网络方案,Flannel、Calico、canel、 kube-router、 Weave、Cilium。CNI 一旦选型后,后期不支持修改。
目前比较常用的时flannel和calico,flannel的功能比较简单,不具备复杂网络的配置能力,calico是比较出色的网络管理插件。
kubelet来调CNI插件时,会到 /etc/cni/net.d/目录下去找插件的配置文件,并读取它,来加载该插件,并让该网络插件来为Pod提供网络服务
默认安装Flannel
flannel vxlan和calico ipip模式都是隧道方案,但是calico的封装协议IPIP的header更小,所以性能比flannel vxlan要好一点点
flannel的host-gw模式,以及calico的bgp模式为路由方案,网络性能好。

Flannel网络插件要怎么部署

flannel适用于小型集群,每个node写静态路由
Flannel 使用虚拟网络来实现网络功能
凡是部署kubelet的节点,都需要部署flannel
1.它支持直接运行为宿主机上的一个守护进程。
3.它也支持运行为一个Pod

flannel的工作方式有3种:
默认使用vxlan
1) VxLAN:
VxLAN有两种工作方式:
a. VxLAN: 这是原生的VxLAN,即直接封装VxLAN首部,UDP首部,IP,MAC首部这种的。
b. DirectRouting: 这种是混合自适应的方式,Host-GW 和 VxLAN 自动切换

2) host-GW:
由宿主机通过查询本地路由表,来做路由转发,实现跨主机的Pod通信,这种模式带来的问题时,当k8s集群非常大时,会导致宿主机上的路由表变得非常巨大

3) UDP: 这是早期使用方式,性能最差的

在flannel的vxlan模式下,ping不在同一节点的pod,流量路径为pod(容器)->cni0->flannel.1-> 本host IP -对端host IP ->flannel.1-> cni0 ->对应的pod(容器)
flannel的host-gw模式下的不同节点上pod访问流量路径如下:
pod(容器)->cni0-> 本host IP -对应host IP -> cni0 ->对应的pod(容器)**而不会经过flannel.1网卡(正常情况应该没有这个网卡)

比较小而简单的集群使用flannel,通常使用flannel+vxlan ,开启DirectRouting
在配置flannel时,一定要注意,不要在半道上,去修改。不足是不能做pod之间的隔离
相同 Node 上的 pod 相互访问是不需要经过 Flannel 的

Calico

官方网址:https://docs.tigera.io/
Calico是一种非常复杂的网络组件,大于50节点时需要自己的etcd数据库集群,可以控制pod之间的通信,像iptables,适用于pod之间有隔离需求
Calico 使用基于路由的方法实现网络功能。每个容器都有一个唯一的 IP 地址,这些 IP 地址由网络拓扑自动分配。每个节点上都有一个 agent,它负责将路由规则下发到节点的内核。这些规则将每个容器的 IP 地址与对应的容器所在节点的 MAC 地址绑定在一起。这样,当容器之间通信时,流量将被路由到相应的节点,然后被路由到目标容器。Calico 还支持多种路由协议,例如 BGP、OSPF 和 Bird。
Calico的开发测试周期包括定期测试数千个节点集群
监听ECTD中心的存储获取事件

Calico的几种模式
  • IPIP模式:适用于互相访问的pod不在同一个网段中,跨网段访问的场景。把 IP 层封装到IP 层的一个 tunnel。作用其实基本上就相当于一个基于IP层的网桥!一般来说,普通的网桥是基于mac层的,根本不需 IP,而这个ipip 则是通过两端的路由做一个 tunnel,把两个本来不通的网络通过点对点连接起来。
  • BGP工作模式:适用于互相访问的pod在同一个网段,适用于大型网络。BGP 边界网关协议(Border Gateway Protocol, BGP):是互联网上一个核心的去中心化自治路由协议。BGP不使用传统的内部网关协议(IGP)的指标
  • Route Reflector 模式(RR)(路由反射):Calico维护的网络在默认是(Node-to-Node Mesh)全互联模式,Calico集群中的节点之间都会相互建立连接,用于路由交换。但是随着集群规模的扩大,mesh模式将形成一个巨大服务网格,连接数成倍增加。这时就需要使用 Route Reflector(路由器反射)模式解决这个问题。

Calico本身支持多种网络模式,从overlay和underlay上区分。Calico overlay 模式,一般也称Calico IPIP或VXLAN模式,不同Node间Pod使用IPIP或VXLAN隧道进行通信。Calico underlay 模式,一般也称calico BGP模式,不同Node Pod使用直接路由进行通信。在overlay和underlay都有nodetonode mesh(全网互联)和Route Reflector(路由反射器)。如果有安全组策略需要开放IPIP协议;要求Node允许BGP协议,如果有安全组策略需要开放TCP 179端口;官方推荐使用在Node小于100的集群,我们在使用的过程中已经通过IPIP模式支撑了100-200规模的集群稳定运行。

当集群规模大于50节点时,应该使用calico-typha 。用于Calico通过Typha直接与Etcd通信,以降低kube-apiserver的负载,可以和kube-apiserver使用一个etcd.
每个Pod/calico-typha可承载100~200个Calico节点的连接请求,最多不要超过200个.

在calico中,全网路由的数目和endpoints的数目一致,通过为node分配网段,可以减少路由数目,但不会改变数量级。
如果有1万个endpoints,那么就至少要有一台能够处理1万条路由的设备。
无论用哪种方式部署始终会有一台设备上存放着calico全网的路由。
当要部署calico网络的时候,第一步就是要确认,网络中处理能力最强的设备最多能设置多少条路由。

通常使用 Calico overlay 模式+IP-in-IP+CrossSubnet
在跨网段的k8s节点的pod间通信时才使用vxlan或ipip进行封包, 同一网段的8s节点的pod间通信则直接使用bgp模式。使用同网段内的k8s节点作为BGP Speaker全互联交换各自的pod子网路由实现互通, 避免封包.

50节点以下
Calico overlay 模式+IP-in-IP+CrossSubnet
50~200节点
Calico overlay 模式+IP-in-IP+CrossSubnet+typha(etcd)

Calico的BGP(RR模式)比cilium的BGP路径更短.

calico优缺点
  • calico的好处是endpoints组成的网络是单纯的三层网络,报文的流向完全通过路由规则控制,没有overlay等额外开销。

  • calico的endpoint可以漂移,并且实现了acl。

  • calico的缺点是路由的数目与容器数目相同,非常容易超过路由器、三层交换、甚至node的处理能力,从而限制了整个网络的扩张。

  • calico的每个node上会设置大量(海量)的iptables规则、路由,运维、排障难度大。

  • calico的原理决定了它不可能支持VPC,容器只能从calico设置的网段中获取ip。

  • calico目前的实现没有流量控制的功能,会出现少数容器抢占node多数带宽的情况。

  • calico的网络规模受到BGP网络规模的限制。

  • 在calico中,全网路由的数目和endpoints的数目一致,通过为node分配网段,可以减少路由数目,但不会改变数量级。

  • 如+ 果有1万个endpoints,那么就至少要有一台能够处理1万条路由的设备。

  • 无论用哪种方式部署始终会有一台设备上存放着calico全网的路由。

  • 当要部署calico网络的时候,第一步就是要确认,网络中处理能力最强的设备最多能设置多少条路由。

Canal

Canal是Flannel和Calico的组合

Cilium

Cilium 是一种基于 eBPF (Extended Berkeley Packet Filter) 技术的网络插件,它使用 Linux 内核的动态插件来提供网络功能,如路由、负载均衡、安全性和网络策略等。
要使用完整的 Cilium 功能, 需要非常新版本的 Linux 内核. 目前官方推荐的 Linux Kernel 是 ≥ 5.10.
Cilium 的网络隔离策略遵循白名单机制,在不创建网络策略的情况下,对于网络不作任何限制,在为指定类型的 pod 集合创建网络策略后,除策略中允许的访问地址外,其它请求都会被拒绝。
Cilium 推荐大于 5.2 的内核版本,从而充分利用 eBPF 的能力。Kubernetes worker 需要打开 TCP 端口 8472(VXLAN)和 TCP 端口 4240(健康检查)。此外,还必须为健康检查启用 ICMP 8/0
默认情况下,Cilium 不允许 Pod 与其他节点上的 Pod 通信。要解决此问题,请启用 Ingress Controller 以使用 “CiliumNetworkPolicy” 进行跨节点路由请求

其不但支持最基本的 pod 之间通信,甚至还支持 L4/L7 层等负载均衡,甚至把 kube-proxy 给干掉了,同时其还自带 service mesh、DNS Proxy、网络追踪等各种乱七八糟你想得到想不到的功能它都有,着实是生猛!
另外由于其是基于 ebpf 的,所以在功能上能实现跳过一些协议栈以及一些过滤阶段等,因此性能上来讲会比其他一些通俗的网络插件要好。
传统防火墙在第 3 层和第 4 层运行,而 Cilium 还能确保 REST/HTTP、gRPC 和 Kafka 等现代第 7 层应用协议的安全(除了在第 3 层和第 4 层执行外)。它能根据应用协议请求条件执行网络策略,例如
• 允许方法为 GET、路径为 /public/.* 的所有 HTTP 请求。拒绝所有其他请求。
• 要求所有 REST 调用都包含 HTTP 标头 X-Token:[0-9]+。

不过他也不是完全没缺点,其主要缺点就在于对内核的要求非常之高,因为其会用到很多 linux 内核高版本才有的功能,同时安装也挺费劲的。它的官网上提供了数十种安装方式,我反正折腾了好久好久才部署好。另外就是 cilium 由于用了很多 ebpf 的方法,导致其非常复杂,不管是代码实现还是流量走向的观察都比较复杂,不像是 flannel,看看主机路由表啥的就能把流量走向看个大概的。

如果您需要更高的性能和更细粒度的安全控制,可以选择Cilium;如果您需要更简单的网络策略和更容易上手的解决方案,则可以选择Calico

带宽: calico+ipip > flannel+vxlan > cilium+vxlan
速度: calico+ipip > flannel+vxlan > cilium+vxlan
稳定性:cilium+vxlan > calico+ipip > flannel+vxlan

如果k8s节点同在同一网段下,没有跨网段节点
50节点以下
flannel+host-gw
Calico+IPIP+crossSubnet

如果k8s节点同在同一网段下,但有少量跨网段需求
50节点以下
flannel+VxLAN+DirectRouting
Calico+IPIP(VXLAN)+crosssubnet+nodetonode mesh
50~100节点
Calico+IPIP(VXLAN)+crosssubnet+etcd+nodetonode mesh
cilium+vlan
100~200节点
Calico+IPIP(VXLAN)+crosssubnet+etcd+Route Reflector
cilium+vlan

如果有高内核,外部BGP条件,跨网段大集群需求
cilium+BGP

有网络隔离需求
Calico/cilium

3/4 层(IP 地址和端口)和第 7 层(API 协议)的隔离需求和网络eBPF流量可见性,pod固定IP需求
cilium

Ingress 选型

https://www.upyun.com/tech/article/524/1.html?utm_source=zhihu&utm_medium=wenz&utm_campaign=wf65g&utm_term=345147856&utm_content=002
Kubernetes Ingress k8s社区的ingres-nginx

K8S 默认的 Nginx ingress
  • https://github.com/kubernetes/ingress-nginx
  • Ingress-NGINX v1.9.3 k8s supported version 1.28, 1.27,1.26, 1.25 Nginx Version 1.21.6
  • 路由匹配:host,path
  • 部署策略:ab部置,金丝雀
  • upstream探测:重试,超时
  • 防护能力:limit-conn,limit-count,limit-req,ip-writelist
  • 使用Nginx config reload,reload 会很严重的影响业务
  • Nginx ingress 的插件开发非常困难
Nginx Ingress
  • ginx公司的nginx-ingress
  • ttps://github.com/nginxinc/kubernetes-ingress
  • 路由匹配:host,path
  • 部署策略:
  • pstream探测:重试,超时,心跳探测
  • 防护能力:
APISIX
  • 路由匹配:path,method,host,header,nginx变量,args变量,自定义函数
  • 部署策略:ab部置,灰度发布,金丝雀
  • upstream探测:重试,超时,心跳探测,熔断
  • 防护能力:limit-conn,limit-count,limit-req,ip-writelist
  • 优势热更新,不需reload
kong ingress
  • 路由匹配:path,method,host,header
  • 部署策略:蓝绿发布,金丝雀
  • upstream探测:心跳探测,熔断
  • 防护能力:limit-conn,limit-count,limit-req,ip-writelist,response limit
Traefik
  • 路由匹配:path,method,host,header,query,path prefix

  • 部署策略:蓝绿部置,灰度发布,金丝雀

  • upstream探测:重试,超时,心跳探测,熔断

  • 防护能力:limit-conn,limit-req,ip-writelist

  • 优势:
    Traefik 是云原生模式,配置文件极其简单,采用分布式配置,同时支持多种自动配置发现。不仅支持 K8s、etcd,Golang 的生态语言支持比较好,且开发成本较低,迭代和测试能力较好

  • 不足:
    扩展能力弱
    不支持 Reload
    性能和功能上不如 Nginx(虽然消耗也较低)

haproxy
Istio Ingress

envoy 平台

Ambassador

envoy 平台

防火墙

集群内部建议不设置防火墙。如设置防火墙可参考下表
多集群联邦模式部署,需要考虑hosts?集群可以访问member?集群的6443 端口。

服务 协议 操作 起始端口 结束端口 备注
ssh TCP allow 22
etcd TCP allow 2379 2380
apiserver TCP allow 6443
calico TCP allow 9099 9100
bgp TCP allow 179
nodeport TCP allow 30000 32767
master TCP allow 10250 10258
dns TCP allow 53
dns UDP allow 53
local-registry TCP allow 5000 离线环境安装
local-apt TCP allow 5080 离线环境安装
rpcbind TCP allow 111 使用 NFS 作为持久化存储
ipip IPIP allow Calico 需要允许 IPIP 协议
服务角色规划
  • Master 节点:Master是Kubernetes 的主节点。Master节点上面主要由四个模块组成:etcd、api server、+ controller manager、scheduler,高可用架构一般建议在3个节点,可以和etcd 融合部署。Master节点上不运+ 行任何用户容器。
  • Etcd节点:etcd 节点在集群规模大于 25 个节点的情况下,可以采用单独节点,推介采用SSD存储作为Etcd 存+ 储数据。节点规模小可以采用和Master 节点融合部署
  • Node 节点:Node在每个节点上运行,为用户业务 Pod 提供 Kubernetes 运行环境。Node 节点一般 + kube-proxy 、kubelet 两个组件。
  • 镜像仓库节点: 私有harbor仓库。
  • 集群内部负载节点:只作为集群内部管理, 主要用途为 K8S API 、KubeSphere API和对外暴露KubeSpher + Web 界面,现有环境中有可用的负载均衡服务,比如硬件的 F5,或者某个公有云、私有云的 slb,也可自已装+ haproxy + keepalive 节点配置软LB。
Master 节点包含服务:
服务 最小规模 用途
Master 节点 3 节点
kube-apiserver 3 副本 Kubernetes REST API
kube-controller-manager 3 副本 Kubernetes 管理控制中心
kube-scheduler 3 副本 Kubernetes 调度器,负责将 Pods 指派到节点上。
etcd 3 副本 键值型数据库 主要用来记录K8s上所有资源的状态。
Node 节点包含服务
服务 最小规模 用途
Node 节点 3 节点
coredns 2 副本 高性能、易扩展的DNS服务端,用于集群内部service?域名访问等()
nodelocaldns 节点数(daemonset 方式运行) 在集群的上运行一个dnsCache daemonset来提高clusterDNS性能和可靠性
kube-proxy 节点数(daemonset?方式运行) Kubernetes Service的通信与负载均衡机制的重要组件
kubelet 节点(节点服务) 每个节点上的主要的“节点代理”,每个节点都会启动 kubelet进程,用来处理 Master 节点下发到本节点的任务。
docker 节点(节点服务) 容器引擎
calico-kube-controller 1 Calico 控制节点
Calico-cni 节点数(daemonset方式运行) CNI插件,用于容器之间网络通信等。
镜像仓库节点
服务 最小规模 用途
Harbor 2 镜像仓库主备架构,主对外提供服务。
集群配比参考
Nodes 数量 Master 数量 Master 配置 数据盘挂载大小
25 3 8C16G 500G以上
100 5 16C32G 800G 以上
250 5-7 16C64G 1T 以上
Etcd 节点配置推荐:
在25节点以内,可以将etcd 节点和Master 融合部署: Nodes 数量 Etcd 数量 Etcd 配置 数据盘挂载SSD 大小
25 3 4核8 G 200G
100 3-5 8 核 16G 500G
250 5-7 8 核 32G 1T
网络CIDR 配置推荐(以Calico 为例):
Nodes 数量 KubePodsCIDR KubeServiceCIDR 备注
25 10.233.0.0/18 10.233.0.0/18 可提供16K IPs
100 10.233.0.0/16 10.233.0.0/16 可提供64K IPs
250 10.0.0.0/14 10.128.0.0/14 可提供256K IPs
日志组件
Nodes 数量 是否外置 推荐 备注
5 内置 Es master 1 副本 es data 2副本
10 内置 Es master 3 副本 es data 3副本 具体可参考日志量和集群存储IO和网络能力,决定是否需要外置。
10节点以上 外置 eck

集群规模参考示例

场景一:小规模

节点数量:3台Master + 3 Node
配置考虑:3Master 8核16G, Node 16核32G 。

场景二:次小规模

节点数量:3 台Master节点 + 25台Nodes以内
配置考虑:3 台Master 8核16G ,25台Nodes 16核32G

需要外置组件:日志

场景三:中型规模

节点数量:5台Master 节点 + 3台Etcd 节点 + 100台Node 节点
配置考虑:5台Master 节点考虑16核32G。
3 台Etcd 节点8核16G 数据盘挂载SSD。
需要外置组件: 日志

场景四:大型规模

节点数量:5台Master 节点 + 5台Etcd节点 + 250台Node节点
配置考虑:5台Master 节点考虑16核32G。
5台Etcd 节点8核16G 数据盘挂载SSD。


所有 pod 都应该设置 limit 和request 数值

所有 pod 都应该设置 limit 和request 数值,否则资源利用率统计很不准。资源不够的时候,没有设置 request 和 limit 的 pod 最先被驱逐,最后是 request=limit 的 pod 被驱逐。集群在使用中,有的资源允许压缩使用,有的不成。CPU、网络I/O可以;内存和磁盘空间不建议。但很多时候 pod 并不是同时使用,因此稍有有一些超额分配是可以的,可以在 limitrange 中的 maxLimitRequestRatio 设置百分比。当然,这个百分比要通过测试实现。也就是说,当资源不够的时候,pod 会被驱逐,根据你能接受的驱 逐pod的 频率,设置评定当时的超分率。当然,超额使用的设置还和每个 namespace 的 qouta 的设置有关。从集群角度看,K8s 整体的 qouta 可以大于整体的可提资源
K8s 节点会预留资源,主要分为两部分 Kube-reserved, system-reserved。当资源利用率超过的可分配资源时(开始侵占预留资源),K8s 开始驱逐内存。K8s 驱逐 pod 的阈值可以设置,也就是说,当节点的资源少于多少的时候,开始驱逐 pod。

容量规划主要是对比 request 资源和实际使用率。根据实际使用率的上浮下浮 20%,我们设定资源的上限、下限预估值。
低估造成资源不够,高估造成资源浪费。如果出现高估,可以减少 request,limit 不变,让 request< limit。如果出现了低估,那降低 limit,让 request=limit。

磁盘和内存驱逐上限

例如在kubelet的启动参数中添加–eviction-hard=memory.available<500Mi,nodefs.available<10%,nodefs.inodesFree<5%,其中nodefs.available参数用于设置根目录使用的阈值。这里的10%表示当根目录使用超过10%时,节点将开始启动驱逐过程。需要注意的是,驱逐过程可能会导致节点上的Pod被删除,因此在调整阈值时需要谨慎。建议在根目录使用接近阈值时就开始进行清理或扩容操作,以避免出现驱逐的情况。

kubelet 默认的关于节点存储的驱逐触发条件:
   1.nodefs.available<10%(容器 volume 使用的文件系统的可用空间,包括文件系统剩余大小和 inode 数量)
   2.imagefs.available<15%(容器镜像使用的文件系统的可用空间,包括文件系统剩余大小和 inode 数量)
nodefs是kubelet目录所在分区,默认在/var/lib/kubelet/目录;imagefs是docker安装目录所在的分区,默认在/var/lib/docker,自定义如/data/docker目录。

kubelet 默认的关于节点内存资源的驱逐触发条件:

    memory.available<100Mi
查看节点的可分配资源:

kubectl describe node node01.k8s.local | grep Allocatable -B 4 -A 3

驱逐配置
--eviction-hard=memory.available<5%,nodefs.available<10%,imagefs.available<10%

--eviction-soft=memory.available<10%,nodefs.available<15%,imagefs.available<15%

--eviction-soft-grace-period=memory.available=2m,nodefs.available=2m,imagefs.available=2m

--eviction-max-pod-grace-period=30

--eviction-minimum-reclaim=memory.available=0Mi,nodefs.available=500Mi,imagefs.available=500Mi
扩容依据

当节点资源使用率超过70% ,建议增加集群节点或进行节点扩容。


目前 Kubernetes 中的业务主要可以分为
  • 业务 API对象
  • 长期伺服型(long-running) Deployment
  • 批处理型(batch) Job
  • 节点后台支撑型(node-daemon) DaemonSet
  • 有状态应用型(stateful application) StatefulSet
  • 资源对象
  • 资源对象 Pod、ReplicaSet、ReplicationController、Deployment、StatefulSet、DaemonSet、Job、+ CronJob、HorizontalPodAutoscaling、Node、Namespace、Service、Ingress、Label、+ CustomResourceDefinition
  • 存储对象 Volume、PersistentVolume、Secret、ConfigMap
  • 策略对象 SecurityContext、ResourceQuota、LimitRange
  • 身份对象 ServiceAccount、Role、ClusterRole
安装顺序参考
  • 基础
  • 容器
  • 私仓
  • 主体
  • ipvs
  • 存储
  • UI
  • ingress

避坑点

参考:https://mp.weixin.qq.com/s/GH-iX0W_d435p4YDgxjHXA

4.14以下linux内核搭配Kubernetes在1.9.x~1.21以下版本 存在cgroup泄漏问题,长时间运行后无法新建pod,升级内核

参考:https://tencentcloudcontainerteam.github.io/2018/12/29/cgroup-leaking/
pod 的 "cannot allocated memory"报错,node 内核日志的“SLUB: Unable to allocate memory on node -1”

原因
创建销毁容器/云主机、登录宿主机、cron 定时任务等会触发创建临时的 memory cgroup,但产生的 cache 内存并不会被主动回收.最多65535个memory cgroup共存

临时解决定时执行
echo 3 > /proc/sys/vm/drop_caches

其化解决方法
内核配置 nokmem 禁用 kmem accounting 功能,修改虚机启动的引导项 grub 中的cgroup.memory=nokmem,让机器启动时直接禁用 cgroup的 kmem 属性
K8s(Kubernetes) 禁用 KernelMemoryAccounting 功能,重新编译kubelet和runc
docker/runc 禁用 KernelMemoryAccounting 功能,重新编译kubelet和runc

内核 4.12 以下tcp_tw_recycle

k8s向外连接时,通过 NAT 方式联网并与服务端交互时,服务端看到的是同一个 IP。也就是说对服务端而言这些客户端实际上等同于一个,可惜由于这些客户端的时间戳可能存在差异。于是乎从服务端的视角看,便可能出现时间戳错乱的现象,进而直接导致时间戳小的数据包被丢弃,具体的表现通常是是客户端明明发送的 SYN,但服务端就是不响应 ACK。
外部机器关闭ip复用。

echo 0 > /proc/sys/net/ipv4/tcp_tw_recycle

由于 tcp_tw_recycle 坑太多,在内核 4.12 之后已移除

5.9以下linux内核,IPVS 模式会启用net.ipv4.vs.conntrack=1,复用TCP连接问题,存在大量TCP短连接场景,不建议使用IPVS,建议替换为iptables模式,会有部分连接多出了1s的延迟的问题。

net.ipv4.vs.conn_reuse_mode=0会出现部分流量被转发到销毁Pod的问题。
net.ipv4.vs.conn_reuse_mode=1会有部分连接多出了1s的延迟的问题

NodePort netfilter 的 SNAT 源端口冲突

大流量下负载到NodePort时,会偶尔有SYN 收到但没响应
conntrack -S 看到 insert_failed 数量在不断增加

解决
不使用源端口选举,在 iptables 的 MASQUERADE 规则如果加 –random-fully 这个 flag 可以让端口选举完全随机,基本上能避免绝大多数的冲突,但也无法完全杜绝。最终决定开发 LB 直接绑 Pod IP,不基于 NodePort,从而避免 netfilter 的 SNAT 源端口冲突问题。

k8s长连接问题

1.长连接服务扩容失效
原因是客户端长连接一直保留在老的Pod容器中,新扩容的Pod没有新的连接过来,导致K8S按照步长扩容第一批Pod之后就停止了扩容操作,而且新扩容的Pod没能承载请求,进而出现服务过载的情况,自动扩容失去了意义.
参照下面减少keepalive_time时间

2.conntrack 表项超时导致tcp长连接中断
采取ipvs代理 部署后在调用gRPC服务时小概率出现Connection reset by peer的错误。

  • nf_conntrack_max:连接跟踪表的大小,建议根据内存计算该值CONNTRACK_MAX = RAMSIZE (in bytes) / + 16384 / (x / 32),并满足nf_conntrack_max=4*nf_conntrack_buckets,默认262144
  • nf_conntrack_buckets:哈希表的大小,(nf_conntrack_max/nf_conntrack_buckets就是每条哈希记录链表+ 的长度),默认65536
  • nf_conntrack_tcp_timeout_established:tcp会话的超时时间,默认是432000 (5天)
sysctl -n net.netfilter.nf_conntrack_max
2310720
sysctl -n net.netfilter.nf_conntrack_tcp_timeout_established
432000
sysctl -n net.netfilter.nf_conntrack_buckets
262144

解决
增加nf_conntrack_max,nf_conntrack_buckets,减少nf_conntrack_tcp_timeout_established ,减少keepalive
64G内存的机器,推荐配置

net.netfilter.nf_conntrack_max=4194304
net.netfilter.nf_conntrack_tcp_timeout_established=300
net.netfilter.nf_conntrack_buckets=1048576

2.Ipvs的连接优化
如果出现连接主动关闭的问题,因为从 client 到 server 经历了一层 ipvs,所以最大的可能就是 ipvs出将连接主动断开,而 client 端还不知情.

原始

net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_intvl = 75

pod中特权模式优化,减少时间

echo 'net.ipv4.tcp_keepalive_time=600'  >> /etc/sysctl.conf
echo 'net.ipv4.tcp_keepalive_probes=10' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_keepalive_intvl=30'  >> /etc/sysctl.conf
sysctl -p

max_syn_backlog 过小 Pod 偶尔存活检查失败

net.ipv4.tcp_max_syn_backlog 默认是 1024,如果短时间内并发新建 TCP 连接太多,SYN 队列就可能溢出,导致部分新连接无法建立。
改成 8096

Kubernete证书使用超长有效期10年,避免证书过期。

验证这些证书的到期时间:

openssl x509 -noout -dates -in $(kubectl config view --minify --output 'jsonpath={.clusters[0].cluster.certificate-authority}')

ipvs/iptables 在集群中不超过1000个服务的时候,iptables 和 ipvs 并无太大的差别,在有5千个服务(4万条规则)时,添加一条规则耗时11分钟.避免使用iptables

磁盘和内存驱逐上限

没有NodeLocal情况下,重启coredns pod导致集群业务解析域名失败5分钟,安装NodeLocal

DNS 解析偶尔 5S 延时

conntrack 表DNAT插入时冲突
解决方案一: 使用 TCP 发送 DNS 请求
resolv.conf 可以加 options use-vc

解决方案二: 避免相同五元组 DNS 请求的并发

resolv.conf 加上 options参数

spec:
      dnsConfig:
        options:
          - name: single-request-reopen

解决方案三: 使用本地 DNS 缓存
每个容器自带一个 DNS 缓存服务。每个节点运行一个 DNS 缓存服务,所有容器都把本节点的 DNS 缓存作为自己的 nameserver。

时间

各node时间必须一致

Secret 和 ConfigMap

Secret 和 ConfigMap使用变量时不支持热更新
ConfigMap 使用subpath时不支持热更新

k8s升级

由于版本的兼容性,只能从一个次要版本升级到另外一个次要版本, 不能跳跃升级。1.19.x → 1.20.y 是可以的.
升级后,因为容器规约的哈希值已更改,所有容器都会被重新启动。

Posted in 安装k8s/kubernetes.

Tagged with , , .


Stable Diffusion 以Docker部署CPU运行在Linux系统

基于文本生成图像的强大模型

Stable Diffusion 的代码开源在 GitHub 上,地址如下:
https://github.com/CompVis/stable-diffusion

SDXL是 v1.5 模型的官方升级版,SDXL 的总参数数量为 66 亿,而 v1.5 为 9.8 亿
SDXL 的默认图像大小是 1024×1024,这比 v1.5 模型的 512×512 大 4 倍
SDXL 1.0 应该在具有 8GB VRAM 的 GPU 上有效工作。但sdwebui现在做不到(需要10G),能做到的只有COMFY UI

Stable Diffusion web UI
https://github.com/AUTOMATIC1111/stable-diffusion-webui
1.9.3 2024/4/23
1.6版本性能强劲,对小显存用户比较友好,不再轻易出现跑SDXL大模型爆显存的情况

cpu 版使用这个
https://github.com/openvinotoolkit/stable-diffusion-webui
This repo is a fork of AUTOMATIC1111/stable-diffusion-webui which includes OpenVINO support through a custom script to run it on Intel CPUs and Intel GPUs.
1.6版本

AMD显卡满血Stable Diffusion(SD+Fooocus+ComfyUI)无脑部署笔记(Linux+ROCm6.1.1)
https://zhuanlan.zhihu.com/p/656480759

Stable-Diffusion-WebUI使用指南
https://blog.csdn.net/qq_39108291/article/details/131025589

stablediffusion与midjouney的区别

1. midjouney的特点:

midjouney是一个商业化产品,用户需要付费才能使用,而且只能通过其官方Discord上的Discord机器人使用。midjouney没有公布其技术细节,但是其生成的图像效果非常惊艳,普通人几乎已经很难分辨出它产生的作品,竟然是AI绘画生成的。
midjouney善于适应实际的艺术风格,创造出用户想要的任何效果组合的图像。它擅长环境效果,特别是幻想和科幻场景,看起来就像游戏的艺术效果。midjouney的提示词门槛低,不需要特别精细的描述也可以出不错的图像。但是缺点是画面不太受控,而且被BAN的敏感词非常多,像bare,nude(裸体)这类词就用不了。

2. stablediffusion的特点:

stablediffusion是一个开源的模型,任何人都可以免费使用(但是需要有GPU来跑),也可以部署到GoogleColab和Drive去薅Tesla T4。stablediffusion是基于latent diffusion model(LDM)的条件扩散模型,采用CLIP text encoder提取的text embeddings作为condition。stablediffusion对当代艺术图像有比较好的理解,可以产生充满细节的艺术作品。除了文生图功能外,还支持图生图、图像重绘、个性化模型训练、可控生成等多种扩展应用。stablediffusion比较适合生成复杂的、有创意的插图。但是缺点是提示词门槛高,手部问题,Lora的兼容性等等。

3.midjouney和stablediffusion的优劣

midjouney和stablediffusion各有优劣之处,具体如下:

① midjouney的优点是:出图质量高、出图稳定、提示词简单、艺术风格丰富、环境效果出色。

②midjouney的缺点是:收费昂贵、只能通过Discord使用、技术细节不透明、画面不太受控、敏感词过多。

③stablediffusion的优点是:开源免费、可本地部署或云端使用、技术原理清晰、扩展应用多样、当代艺术理解好。

④stablediffusion的缺点是:需要GPU资源、提示词门槛高、手部问题突出、Lora兼容性差。

       那么对于普通人来说,选择stablediffusion可能比选择midjouney更合适,原因如下:

①stablediffusion是免费的,而midjouney是收费的,对于预算有限的普通人来说,stablediffusion更划算。

②stablediffusion是开源的,而midjouney是闭源的,对于想要了解AI绘图技术原理和细节的普通人来说,stablediffusion更透明。

③stablediffusion是灵活的,而midjouney是固定的,对于想要尝试不同功能和插件的普通人来说,stablediffusion更多样。

④stablediffusion是创新的,而midjouney是成熟的,对于想要挑战自己和发挥想象力的普通人来说,stablediffusion更有趣。

总的来说,如果您会使用midjouney,就相当于您学会了买车票搭车去某个地方,你只能选择路线,而您会使用stablediffusion,就相当于您自己买了一辆车,考了一个驾照,想去哪里就去哪里,想怎么开车就怎么开车(划重点)

安装要求

最核心的关键点:看显卡、看内存、看硬盘、看CPU。其中最重要的是看显卡,显卡N卡(英伟达Nvida显卡),最低10系起步,显存最低4G,6G及格;内存最低8G,16G及格;硬盘可用空间最好有个500G朝上,固态最佳,机械硬盘也没多大问题。CPU其实没太大要求,有好显卡的,CPU一般不会很差。

可能的误区

  • 1.误区1:必须用linux或者windows
    mac os也可以,但是同样在于其它的坑多,不建议在mac os上使用,当然我也没试过。
    windows和linux这个图形界面会占用显存,特别是显存小的时候更明显(windows只有server版可以只装命令行用)

  • 2.误区2:必须用N卡
    N卡坑少,出问题容易找到答案,并不是只能N卡。A卡、cpu也可以、i卡理论上可以,使用难度较大。Nvidia显卡(Cuda)或AMD显卡(ROCm)

  • 3.误区3:必须用conda
    用conda的原因在于很多开发者通常需要多个python环境,个人部署直接装在系统就行。

请放弃尝试在Win下通过虚拟机、WSL安装ROCm;

windows安装

推荐哔哩哔哩站秋叶做的整合包A绘世启动器.支持cpu/N卡/A卡
由于网络下载问题,这里使用的模型直接使用秋叶整合包中下载的。

最新一次更新整合包版本v4.8,24 年 4 月更新。
网盘:https://pan.quark.cn/s/2c832199b09b
解压密码:bilibili@秋葉aaaki
https://www.bilibili.com/video/BV1iM4y1y7oA/?spm_id_from=333.976.0.0

模型文件

Stable-diffusion支持五种模型文件,Checkpoint、Embedding、Hypernetwork、Lora和VAE。

  • 1.Checkpoint
    Checkpoint模型就是我们在webui的Stable Diffusion checkpoint中选择的模型。Checkpoint模型我把它理解为AI的记忆,它控制着AI能画出什么,画出的东西长什么样。
  • 2.Lora
    Lora模型是一种生成对抗网络模型,主要用对Checkpoint模型进行定向的微调。个人理解是用来做Checkpoint模型提示词重映射的。比如,在一个Checkpoint模型中,提示词“猫”对应形象是“加菲猫”,那么Lora就可以将“猫”这个提示词重映射,使其对应的形象变成HelloKitty,那么在加持Lora模型的Checkpoint模型上输入“猫”这个提示词后AI将不再生成加菲猫,而全部生成HelloKitty。
  • 3.Embedding
    在Stable diffuion中,Embedding模型提供了一种向已有模型嵌入新内容的方式,Embedding模型可以使用很少的图片数据,来生成一个具有新的风格或者人物形象的模型,并且可以使用特定的提示词来映射这些特征。
  • 4.Hypernetworks
    Hypernetworks又叫超网络,Hypernetworks模型是一种风格化文件,可以为AI生成的图像应用指定画风。如,同样是画一个HelloKitty,在没有应用Hypernetworks模型的情况,画出来的HelloKitty就是一只正常的HelloKitty,如果给AI应用一个金享泰画风的Hypernetworks模型,那么AI画出来的HelloKitty就变成一只油腻的HelloKitty。
  • 5.VAE
    VAE的作用就是在第一章中讲到的将图片从潜空间的压缩数据解码变成一张正常的图片,不同的VAE会影响AI出图的色调,如果当我们不使用VAE时,AI生成的图片均会有一层灰蒙蒙的感觉,使用VAE会使图片的饱和度有所区别。
  • 6.AestheticGradients
    AestheticGradients(美学渐变)是以插件的形式存在一种模型修改技术,AestheticGradients模型需要依赖AestheticGradients插件才能使用,效果和Hypernetworks差不多,但是基于AestheticGradients插件提供了更多的可调节参数,而Hypernetworks的参数是已经定死了不可更改的。

相关网站

吐司
在线生成,提示词,模型下载
https://tusi.cn/

huggingface
国内不能访问
https://huggingface.co/

c站
Civitai 专门收集和分享Stable Diffusion相关的模型
收集并分享1700+经过筛选的Stable Diffusion模型文件,免费下载。
提供1万+带提示语的示例图片,供用户学习描述内容的方法。
https://www.civita.com
国内镜像
https://civitai.work/

哩布哩布AI
收集了很多不同类型的Stable Diffusion模型,在线生成,下载这些AI生成图片和视频的模型
https://www.liblib.art/

AI提示词
https://www.4b3.com/

AI 作图知识库(教程): https://guide.novelai.dev/
标签超市(解析组合): https://tags.novelai.dev/
原图提取标签: https://spell.novelai.dev/

模型分享下载链接:https://pan.quark.cn/s/32f374eef667

AI绘图的用法拓展

  • ControlNet
    ControlNet的原理主要是使用OpenCV的一些识别算法,如姿势识别、手势识别、边缘检测、深度检测等,先对参考图做一层机器视觉方面的预处理,生成身体骨骼特征点、手势骨骼特征点、描边图、深度图等中间图,然后再让AI参考这些中间图进行创作

  • 制作全景图
    并接360图片

  • mov2mov插件
    https://github.com/Scholar01/sd-webui-mov2mov
    生成同步的视频文件

  • 人物换装

  • OutPainting
    outpainting是官方提供的一项AI图像扩展技术,AI可以根据已有的图像来扩展图像之外的画面。

  • SadTalker
    唇型同步

  • 生成类似的图
    这个功能在通过photoshopP图之后,使用AI来融合P图中的看起来比较违和的元素时非常有用,有了这个功能我们就可以快速的使用PS往图中加入我们想要的元素,然后使用AI来融合,当然出图的效果还是取决于大模型;

  • 小图高清重绘

  • 超清放大

准备虚拟机

virtualbox 虚拟一台rock9.3
10核/17G内存/120G硬盘

查看环境

查看系统版本

cat /etc/redhat-release
Rocky Linux release 9.3 (Blue Onyx)

查看内核版本

uname -a
Linux localhost.localdomain 5.14.0-362.8.1.el9_3.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Nov 8 17:36:32 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

查看ssh及openssl 版本

ssh -V
OpenSSH_8.7p1, OpenSSL 3.0.7 1 Nov 2022
不升级

python版本

python -V
Python 3.9.18

glibc版本

ldd –version
ldd (GNU libc) 2.34

rocky9上打开加密兼容

便于低版本ssh 连接
update-crypto-policies –show
update-crypto-policies –set LEGACY

修改ip

查看当前ip

ip a
nmcli device show
nmcli con show

使用配制文件修改

vi /etc/NetworkManager/system-connections/enp0s3.nmconnection

[ipv4]
method=manual
address1=192.168.244.14/24,192.168.244.1
dns=223.5.5.5;1.1.1.1

重新载入生效

nmcli connection reload
nmcli connection down enp0s3 && nmcli connection up enp0s3

主机名设定

hostnamectl set-hostname dev-ai-diffusion.local

hostnamectl status
 Static hostname: dev-ai-diffusion.local
       Icon name: computer-vm
         Chassis: vm 

                            Machine ID: 45d4ec6ccf3646248a8b9cc382baf29d
         Boot ID: 0b6cfd83e8534a1f81f08de3962b8ba9
  Virtualization: oracle
Operating System: Rocky Linux 9.3 (Blue Onyx)      
     CPE OS Name: cpe:/o:rocky:rocky:9::baseos
          Kernel: Linux 5.14.0-362.8.1.el9_3.x86_64
    Architecture: x86-64
 Hardware Vendor: innotek GmbH
  Hardware Model: VirtualBox
Firmware Version: VirtualBox

安装中文语言包

localectl list-locales |grep zh
dnf list |grep glibc-langpack
dnf install glibc-langpack-zh

关防火墙

systemctl stop firewalld
systemctl disable firewalld

selinux

setenforce 0 && sed -i ‘/SELINUX/s/enforcing/disabled/’ /etc/selinux/config

vim 打开黏贴模

echo ‘set paste’ >> ~/.vimrc

时区

timedatectl set-timezone Asia/Shanghai

启用启动脚本

systemctl enable rc-local.service
systemctl start rc-local.service
systemctl status rc-local.service

chmod +x /etc/rc.d/rc.local
chmod +x /etc/rc.local

常用工具

yum -y install wget vim net-tools telnet yum-utils device-mapper-persistent-data lvm2 tar curl lrzsz rsync psmisc sysstat lsof

docker yum

step 1: 安装必要的一些系统工具

sudo yum install -y yum-utils device-mapper-persistent-data lvm2

Step 2: 添加软件源信息

sudo yum-config-manager –add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

Step 3

sudo sed -i ‘s+download.docker.com+mirrors.aliyun.com/docker-ce+’ /etc/yum.repos.d/docker-ce.repo

Step 4: 更新并安装Docker-CE

sudo yum makecache fast
sudo yum -y install docker-ce

Installed:
  container-selinux-3:2.229.0-1.el9.noarch          containerd.io-1.6.31-3.1.el9.x86_64           docker-buildx-plugin-0.14.0-1.el9.x86_64     docker-ce-3:26.1.2-1.el9.x86_64      docker-ce-cli-1:26.1.2-1.el9.x86_64    
  docker-ce-rootless-extras-26.1.2-1.el9.x86_64     docker-compose-plugin-2.27.0-1.el9.x86_64     fuse-common-3.10.2-8.el9.x86_64              fuse-overlayfs-1.13-1.el9.x86_64     fuse3-3.10.2-8.el9.x86_64              
  fuse3-libs-3.10.2-8.el9.x86_64                    libslirp-4.4.0-7.el9.x86_64                   slirp4netns-1.2.3-1.el9.x86_64               tar-2:1.34-6.el9_1.x86_64           

注意:官方软件源默认启用了最新的软件,安装指定版本的Docker-CE
yum list docker-ce.x86_64 –showduplicates | sort -r

docker-ce.x86_64               3:26.1.2-1.el9                  docker-ce-stable 
docker-ce.x86_64               3:26.1.2-1.el9                  @docker-ce-stable
docker-ce.x86_64               3:26.1.1-1.el9                  docker-ce-stable 

yum -y install docker-ce-[VERSION]

Step 5: 开启Docker服务

sudo service docker start

查看版本

docker version

Engine:
  Version:          26.1.2
  API version:      1.45 (minimum version 1.24)
  Go version:       go1.21.10
  Git commit:       ef1912d
  Built:            Wed May  8 13:59:54 2024
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.31
  GitCommit:        e377cd56a71523140ca6ae87e30244719194a521
 runc:
  Version:          1.1.12
  GitCommit:        v1.1.12-0-g51d5e94
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

docker加速

vi /etc/docker/daemon.json

{
"registry-mirrors":["https://docker.nju.edu.cn/"]
}

docker nvidia驱动

非必要,使用N卡时安装

yum install -y nvidia-docker2

systemctl daemon-reload
systemctl enable docker
systemctl restart docker

git 安装

yum install git

使用三方现有镜像安装

下载Stable Diffusion Docker 相关镜像

要下载Stable Diffusion的Docker镜像,您可以使用以下命令:
官方镜像
docker pull diffusion/stable:latest
docker pull kestr3l/stable-diffusion-webui

其它

腾讯加速
docker pull gpulab.tencentcloudcr.com/ai/stable-diffusion:1.0.8

docker.io 中的民间镜像
docker pull bobzhao1210/diffusion-webui

国外镜像

docker pull siutin/stable-diffusion-webui-docker:latest-cpu
docker pull siutin/stable-diffusion-webui-docker:latest-cuda

国内镜像

docker pull registry.cn-hangzhou.aliyuncs.com/sunsharing/stable-diffusion-webui-docker:latest-cpu

阿里官方gpu镜像,比较新

docker pull egs-registry.cn-hangzhou.cr.aliyuncs.com/egs/sd-webui:4.3.5-full-pytorch2.1.2-ubuntu22.04

使用阿里gpu镜像

docker pull egs-registry.cn-hangzhou.cr.aliyuncs.com/egs/sd-webui:4.3.5-full-pytorch2.1.2-ubuntu22.04

docker images

REPOSITORY                                              TAG                                   IMAGE ID       CREATED         SIZE
egs-registry.cn-hangzhou.cr.aliyuncs.com/egs/sd-webui   4.3.5-full-pytorch2.1.2-ubuntu22.04   22226c589a11   3 weeks ago     34.7GB

镜像中相关版本
version: 1.6.0  •  python: 3.10.10  •  torch: 2.1.2+cu118  •  xformers: N/A  •  gradio: 3.41.2

下载标准sd-1.5模型:

存放到models/Stable-diffusion ,使用GPU时下载,不支持cpu运行 ,如果没有ui启动时会尝试自动下载 ,4g左右

mkdir /host  
cd /host  
wget https://aiacc-inference-public-v2.oss-accelerate.aliyuncs.com/aiacc-inference-webui/models/v1-5-pruned-emaonly.safetensors

下载国内 AnythingV5_v5PrtRE.safetensors 2g左右

wget https://api.tusiart.com/community-web/v1/model/file/url/v2?modelFileId=600998819589521712 AnythingV5_v5PrtRE.safetensors

webui启动时必需要一个大模型,这个支持cpu.

Stable-diffusion WebUI文件夹功能

  • localizations: 汉化包
  • configs: 配制文件
  • embeddings:存放美术风格文件的目录,美术风格文件一般以.pt结尾,大小在几十K左右;
  • extensions:存放扩展插件的目录,我们下载的WebUI的插件就放在这个目录里,WebUI启动时会自动读取插件,插件目录都是git库,可以直接通过git更新;
  • extensions-builtin:存放WebUI内置的扩展;
  • models/hypernetworks:存放风格化文件的目录,风格化文件是配合Prompt使用的,以使AI会出对应风格的图片,风格化文件也以.pt结尾,大小在几百MB左右;
  • models/Lora:存放Lora的文件的目录,Lora文件是用来调整模型的,可以重映射模型文件的Prompt映射,使AI在相应的提示词下按照Lora的样式绘制,Lora文件一般以.safetensors结尾,大小在几百MB左右;
  • models/Stable-diffusion:存放模型的文件的目录,AI绘画时的采样基本从这个文件里采,影响图片的整体样式与画风,一般以.ckpt或.safetensors结尾,大小在几个G左右;
  • models/VAE:存放VAE文件的目录,VAE文件会影响图片整体的色调,如在刚开始玩WebUI时画出的图都比较灰,就是因为WebUI默认没有为我们设置VAE导致的,VAE文件一般以.ckpt或.vae.pt结尾,大小在几百MB或几个G不等;
  • outputs/extras-images:AI放大的原图的默认保存路径;
  • outputs/img2img-grids:批量图生图时的缩略图原图的默认保存路径;
  • outputs/img2img-images:图生图的原图的默认保存路径;
  • outputs/txt2img-grids:批量文生图时的缩略图原图的默认保存路径;
  • outputs/txt2img-images:文生图的原图的默认保存路径;

这些路径我们是可以在WebUI的设置界面修改成自定义路径的。

  • scripts:存放第三方脚本的目录;
  • venv:这个文件夹是WebUI首次运行时配置运行环境自己创建的,出现运行环境的问题时,可以删掉它让WebUI重新生成。
  • repositories: 启动后载入python模块代码,会影响是用gpu还是cpu,stablediffusion,taming-transfomers,stable-diffusion,k-diffusion-sd,CodeFormer,BLIP
  • style.csv 存储当前Prompt和Nagetive prompt的提示词作为提示词模板,目前WebUI没有提供在UI中删除提示词模板的功能,想要删除不需要的提示词模板,我们需要通过修改styles.csv文件

拉取cpu版stable-diffusion-webui

拉取cpu版stable-diffusion-webui
cd /host && git clone https://github.com/openvinotoolkit/stable-diffusion-webui.git ./stable-diffusion-webui-cpu

cpu版和gpu版主要差异文件

/modules/launch_utils.py
/requirements.txt
/requirements_versions.txt
/scripts/openvino_accelerate.py

创建启动变量及目录

h_dir=/host # host dir
h_mdir=/host/models # host models dir
c_dir=/workspace/stable-diffusion-webui # container dir
c_mdir=/workspace/stable-diffusion-webui/models # container dir

#mkdir -p ${h_dir}/{localizations,configs,config_states,outputs,embeddings,extensions,extensions-builtin,scripts,repositories}
#mkdir -p ${h_mdir}/{Stable-diffusion,hypernetworks,ControlNet,Lora,VAE,VAE-approx}
cd $h_mdir

cat >> /etc/profile <<EOF
export h_dir=/host
export h_mdir=/host/models # host models dir
export c_dir=/workspace/stable-diffusion-webui # container dir
export c_mdir=/workspace/stable-diffusion-webui/models # container dir
EOF

数据持久化

#先临时启动
docker run -itd --network=host --name=sd
-v /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime \
-p 7860:7860 egs-registry.cn-hangzhou.cr.aliyuncs.com/egs/sd-webui:4.3.5-full-pytorch2.1.2-ubuntu22.04 bash

#复制容器内已存在文件到宿主机
cdirname='localizations configs outputs embeddings extensions extensions-builtin scripts'  
for cname in $cdirname; do echo ${c_dir}/${cname}; docker cp sd:${c_dir}/${cname} ${h_dir}/; done
docker cp sd:${c_dir}/webui-user.sh .

docker exec sd ls models/Stable-diffusion

docker stop sd
docker rm sd

ls ${h_dir}/models/Stable-diffusion
anything-v5-PrtRE.safetensors  'Put Stable Diffusion checkpoints here.txt'

# 复制python包 8.4G
docker cp sd:/root/miniconda3/lib/python3.10/site-packages /host/

# 复制大模型
mv /host/v1-5-pruned-emaonly.safetensors  /host/models/Stable-diffusion

# 复制出config.json
docker cp sd:/workspace/stable-diffusion-webui/config.json .

准备start.sh
vi start.sh
source ./webui-user.sh
python -u ./launch.py --listen --port 5001  --skip-install

启动容器

docker run -itd --network=host --name=sd \
-e COMMANDLINE_ARGS='--use-cpu all --skip-torch-cuda-test --precision full --no-half --no-half-vae  --api' \
-v /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime \
-v ${h_dir}/site-packages:/root/miniconda3/lib/python3.10/site-packages \
-v ${h_dir}/stable-diffusion-webui-cpu:/workspace/stable-diffusion-webui \
-v ${h_mdir}/Stable-diffusion/:${c_mdir}/Stable-diffusion/ \
-v ${h_mdir}/ControlNet/:${c_mdir}/ControlNet/ \
-v ${h_mdir}/VAE/:${c_mdir}/VAE/ \
-v ${h_mdir}/Lora/:${c_mdir}/Lora/ \
-v ${h_mdir}/hypernetworks/:${c_mdir}/hypernetworks/ \
-v ${h_dir}/style.csv:${c_dir}/style.csv \
-v ${h_dir}/outputs/:${c_dir}/outputs/ \
-v ${h_dir}/localizations/:${c_dir}/localizations/ \
-v ${h_dir}/configs/:${c_dir}/configs/ \
-v ${h_dir}/config_states/:${c_dir}/config_states/ \
-v ${h_dir}/repositories/:${c_dir}/repositories/ \
-v ${h_dir}/extensions/:${c_dir}/extensions/ \
-v ${h_dir}/extensions-builtin/:${c_dir}/extensions-builtin/ \
-v ${h_dir}/webui-user.sh:${c_dir}/webui-user.sh \
-v ${h_dir}/start.sh:${c_dir}/start.sh \
egs-registry.cn-hangzhou.cr.aliyuncs.com/egs/sd-webui:4.3.5-full-pytorch2.1.2-ubuntu22.04 bash ./start.sh

容器启动后,SD-webui服务自动启动。如果需要自定义服务启动命令或者端口,请参照下列命令进行修改:

docker exec -it sd /bin/bash

gpu方式运行

python -u ./launch.py –ckpt-dir ./ckpts –listen –port 7860 –enable-insecure-extension-access –disable-safe-unpickle –api –xformers –skip-install

cpu方式运行变量,方便docker 启动时运行

cd /workspace/stable-diffusion-webui
echo ‘export COMMANDLINE_ARGS="–use-cpu all –skip-torch-cuda-test –precision full –no-half –no-half-vae"’ >> ./webui-user.sh

cpu 方式手动运行

python -u ./launch.py –listen –port 5001 –use-cpu all –skip-torch-cuda-test –precision full –no-half –no-half-vae –api –skip-install
python -u ./launch.py –listen –port 5001 –skip-install

开机启动

echo ‘docker start sd’ >> /etc/rc.local

访问

运行成功后在浏览器输入 http://ip:5001 就可以使用

控制台会输出日志

Python 3.10.10 (main, Mar 21 2023, 18:45:11) [GCC 11.2.0]
Version: 1.6.0
Commit hash: e5a634da06c62d72dbdc764b16c65ef3408aa588
Launching Web UI with arguments: --listen --port 5001 --skip-install --use-cpu all --skip-torch-cuda-test --precision full --no-half --no-half-vae
WARNING[XFORMERS]: xFormers can't load C++/CUDA extensions. xFormers was built for:
    PyTorch 2.1.2+cu118 with CUDA 1108 (you have 2.1.0+cu121)
    Python  3.10.13 (you have 3.10.10)
  Please reinstall xformers (see https://github.com/facebookresearch/xformers#installing-xformers)
  Memory-efficient attention, SwiGLU, sparse and more won't be available.
  Set XFORMERS_MORE_DETAILS=1 for more details
No module 'xformers'. Proceeding without it.
Warning: caught exception 'Found no NVIDIA driver on your system. Please check that you have an NVIDIA GPU and installed a driver from http://www.nvidia.com/Download/index.aspx', memory monitor disabled
Loading weights [7f96a1a9ca] from /workspace/stable-diffusion-webui/models/Stable-diffusion/anything-v5-PrtRE.safetensors
Creating model from config: /workspace/stable-diffusion-webui/configs/v1-inference.yaml
2024-05-15 15:07:04,153 - ControlNet - INFO - ControlNet UI callback registered.
Running on local URL:  http://0.0.0.0:5001

To create a public link, set `share=True` in `launch()`.
IIB Database file has been successfully backed up to the backup folder.
Startup time: 19.6s (import torch: 2.5s, import gradio: 0.8s, setup paths: 0.3s, other imports: 0.4s, load scripts: 11.3s, create ui: 1.4s, gradio launch: 2.3s, app_started_callback: 0.3s).
Loading VAE weights specified in settings: /workspace/stable-diffusion-webui/models/VAE/vae-ft-mse-840000-ema-pruned.safetensors
Applying attention optimization: InvokeAI... done.
Model loaded in 4.9s (load weights from disk: 0.1s, create model: 1.8s, apply weights to model: 1.1s, apply float(): 1.5s, load VAE: 0.2s, calculate empty prompt: 0.1s).
[W NNPACK.cpp:64] Could not initialize NNPACK! Reason: Unsupported hardware.
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 20/20 [02:58<00:00,  8.94s/it]
Total progress: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 20/20 [02:56<00:00,  8.83s/it]
Total progress: 100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 20/20 [02:56<00:00,  8.65s/it]

CPU生成一张础基图3分钟左右

docker全新安装

以ubuntu:22.04 做基础镜像
docker pull ubuntu:22.04
docker images

REPOSITORY                                              TAG                                   IMAGE ID       CREATED         SIZE
ubuntu                                                  22.04                                 52882761a72a   2 weeks ago     77.9MB

进入容器

docker run -itd --network=host --name=ub \
-v /usr/share/zoneinfo/Asia/Shanghai:/etc/localtime \
ubuntu:22.04 bash 
docker exec -it ub /bin/bash

cat /etc/issue.net 
Ubuntu 22.04.4 LTS

apt-get update
apt-get -y install --reinstall ca-certificates
cp /etc/apt/sources.list /etc/apt/sources.bak.list 

cat /etc/apt/sources.list

#阿里加速
#sed -n 's/http:\/\/.*ubuntu.com/https:\/\/mirrors.aliyun.com/p' /etc/apt/sources.list
sed -i 's/http:\/\/.*ubuntu.com/https:\/\/mirrors.aliyun.com/g' /etc/apt/sources.list

#清华加速
#echo "deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse\ndeb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse\ndeb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse\ndeb http://security.ubuntu.com/ubuntu/ jammy-security main restricted universe multiverse" > /etc/apt/sources.list

#工具包
apt-get update && apt-get install -y sudo net-tools inetutils-ping procps curl wget vim telnet locales git zhcon fonts-wqy-microhei fonts-wqy-zenhei xfonts-wqy lsrzsz unzip tree

#相关包
apt-get install -y mesa-utils libglib2.0-0

sed -i 's/# zh_CN.UTF-8 UTF-8/zh_CN.UTF-8 UTF-8/' /etc/locale.gen && locale-gen

miniconda 安装

https://docs.anaconda.com/free/miniconda/

cd /root
mkdir -p ~/miniconda3
#wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda.sh
wget https://repo.anaconda.com/miniconda/Miniconda3-py310_22.11.1-1-Linux-x86_64.sh -O ~/miniconda.sh
bash ~/miniconda.sh -b -u -p ~/miniconda3
rm -rf ~/miniconda.sh

~/miniconda3/bin/conda init bash
~/miniconda3/bin/conda init zsh

no change     /root/miniconda3/condabin/conda
no change     /root/miniconda3/bin/conda
no change     /root/miniconda3/bin/conda-env
no change     /root/miniconda3/bin/activate
no change     /root/miniconda3/bin/deactivate
no change     /root/miniconda3/etc/profile.d/conda.sh
no change     /root/miniconda3/etc/fish/conf.d/conda.fish
no change     /root/miniconda3/shell/condabin/Conda.psm1
no change     /root/miniconda3/shell/condabin/conda-hook.ps1
no change     /root/miniconda3/lib/python3.10/site-packages/xontrib/conda.xsh
no change     /root/miniconda3/etc/profile.d/conda.csh
modified      /root/.bashrc

#载入变量
source /root/.bashrc

(base) root@dev-ai-diffusion:~# conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
(base) root@dev-ai-diffusion:~# conda config --set show_channel_urls yes
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

conda -V
conda 22.11.1

设置不自动激活conda base 环境

再次重启终端之后,你会发现每次打开终端默认都会自动进入到miniconda的base环境中,终端中多了“base”字样。这样会拖慢终端打开速度,并且有可能干扰到其它软件的安装。要退出的话,必须每次打开终端之后先执行conda deactivate命令,让人很难受。执行如下命令,便可以解决终端每次打开都进入conda的base环境的问题
conda config –set auto_activate_base false

python –version
Python 3.10.8

创建python3.10.10

conda create -n python_3.10.10 python=3.10.10
(python_3.10.10) root@dev-ai-diffusion:~# python –version
Python 3.10.10

查看有多少个环境

conda info –envs #

# conda environments:
#
base                     /root/miniconda3
python_3.10.10        *  /root/miniconda3/envs/python_3.10.10

设定默认环境
conda config –set default_environment python_3.10.10

激活环境
conda activate python_3.10.10

退出
conda deactivate

删除环境
conda remove –name test –all

pip install –upgrade pip setuptools wheel

下载 stable-diffusion-webui 仓库
mkdir /workspace && cd /workspace
groupadd -g 1000 website && \
useradd -u 1000 -G website -s /sbin/nologin www

stable-diffusion-webui

40m左右
cpu版
git clone https://github.com/openvinotoolkit/stable-diffusion-webui.git ./stable-diffusion-webui-cpu
gpu版
git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git ./stable-diffusion-webui-gpu

ln -s stable-diffusion-webui-cpu stable-diffusion-webui

然后依次下载以下仓库,并切换到合适的版本以避免可能的版本适配问题:

mkdir -p /workspace/common/repositories && cd /workspace/common/repositories

stablediffusion
git clone https://github.com/Stability-AI/stablediffusion.git ./repositories/stable-diffusion-stability-ai

taming-transformers
git clone https://github.com/CompVis/taming-transformers.git ./repositories/taming-transformers

k-diffusion
git clone https://github.com/crowsonkb/k-diffusion.git ./repositories/k-diffusion

CodeFormer
git clone https://github.com/sczhou/CodeFormer.git ./repositories/CodeFormer

BLIP
git clone https://github.com/salesforce/BLIP.git ./repositories/BLIP

generative-models
git clone https://github.com/Stability-AI/generative-models.git ./repositories/generative-models

一共758M

cd /workspace/stable-diffusion-webui/
cat requirements.txt
安装 requirements.txt 中的依赖包

首先确定torch版本和下载的url,不同平台cpu/gpu 使用下列url来确认
https://pytorch.org/get-started/locally/

pip install torch torchvision -i https://pypi.tuna.tsinghua.edu.cn/simple

cpu

pip install torch==2.1.0 torchvision==0.16.0 torchaudio –index-url https://download.pytorch.org/whl/cpu

pip install tb-nightly
pip install tb-nightly -i https://mirrors.aliyun.com/pypi/simple

pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

说明:

必须先安装 torch:因为 basicsr 的安装程序会 import torch.
安装 tb-nightly:清华源缺少这个包,但安装 basicsr 时需要它,所以先不换源把它安装上。
安装其他依赖包
pip install ftfy regex tqdm -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install git+https://github.com/openai/CLIP.git
pip install open_clip_torch xformers -i https://pypi.tuna.tsinghua.edu.cn/simple

Collecting open_clip_torch
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/d9/d2/6ae2ee32d0d2ea9982774920e0ef96d439ee332f459f6d8a941149b1b4ad/open_clip_torch-2.24.0-py3-none-any.whl (1.5 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.5/1.5 MB 2.3 MB/s eta 0:00:00
Collecting xformers
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/32/e7/27003645ef99e7571fb6964cd2f39da3f1b3f3011aa00bb2d3ac9b790757/xformers-0.0.26.post1-cp310-cp310-manylinux2014_x86_64.whl (222.7 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 222.7/222.7 MB 2.0 MB/s eta 0:00:00
Requirement already satisfied: torch>=1.9.0 in /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages (from open_clip_torch) (2.1.0+cpu)
Requirement already satisfied: torchvision in /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages (from open_clip_torch) (0.16.0+cpu)
Requirement already satisfied: regex in /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages (from open_clip_torch) (2024.5.10)
Requirement already satisfied: ftfy in /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages (from open_clip_torch) (6.2.0)
Requirement already satisfied: tqdm in /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages (from open_clip_torch) (4.66.4)
Collecting huggingface-hub (from open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/21/2b/516f82c5ba9beb184b24c11976be2ad5e80fb7fe6b2796c887087144445e/huggingface_hub-0.23.0-py3-none-any.whl (401 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 401.2/401.2 kB 2.6 MB/s eta 0:00:00
Collecting sentencepiece (from open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/a6/27/33019685023221ca8ed98e8ceb7ae5e166032686fa3662c68f1f1edf334e/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.3 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.3/1.3 MB 4.5 MB/s eta 0:00:00
Requirement already satisfied: protobuf in /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages (from open_clip_torch) (4.25.3)
Collecting timm (from open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/68/99/2018622d268f6017ddfa5ee71f070bad5d07590374793166baa102849d17/timm-0.9.16-py3-none-any.whl (2.2 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.2/2.2 MB 3.1 MB/s eta 0:00:00
Requirement already satisfied: numpy in /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages (from xformers) (1.26.3)
Collecting torch>=1.9.0 (from open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/43/e5/2ddae60ae999b224aceb74490abeb885ee118227f866cb12046f0481d4c9/torch-2.3.0-cp310-cp310-manylinux1_x86_64.whl (779.1 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 779.1/779.1 MB 917.4 kB/s eta 0:00:00
Requirement already satisfied: filelock in /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages (from torch>=1.9.0->open_clip_torch) (3.13.1)
Requirement already satisfied: typing-extensions>=4.8.0 in /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages (from torch>=1.9.0->open_clip_torch) (4.9.0)
Requirement already satisfied: sympy in /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages (from torch>=1.9.0->open_clip_torch) (1.12)
Requirement already satisfied: networkx in /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages (from torch>=1.9.0->open_clip_torch) (3.2.1)
Requirement already satisfied: jinja2 in /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages (from torch>=1.9.0->open_clip_torch) (3.1.3)
Requirement already satisfied: fsspec in /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages (from torch>=1.9.0->open_clip_torch) (2024.2.0)
Collecting nvidia-cuda-nvrtc-cu12==12.1.105 (from torch>=1.9.0->open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/b6/9f/c64c03f49d6fbc56196664d05dba14e3a561038a81a638eeb47f4d4cfd48/nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-manylinux1_x86_64.whl (23.7 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 23.7/23.7 MB 3.7 MB/s eta 0:00:00
Collecting nvidia-cuda-runtime-cu12==12.1.105 (from torch>=1.9.0->open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/eb/d5/c68b1d2cdfcc59e72e8a5949a37ddb22ae6cade80cd4a57a84d4c8b55472/nvidia_cuda_runtime_cu12-12.1.105-py3-none-manylinux1_x86_64.whl (823 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 823.6/823.6 kB 4.2 MB/s eta 0:00:00
Collecting nvidia-cuda-cupti-cu12==12.1.105 (from torch>=1.9.0->open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/7e/00/6b218edd739ecfc60524e585ba8e6b00554dd908de2c9c66c1af3e44e18d/nvidia_cuda_cupti_cu12-12.1.105-py3-none-manylinux1_x86_64.whl (14.1 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 14.1/14.1 MB 4.0 MB/s eta 0:00:00
Collecting nvidia-cudnn-cu12==8.9.2.26 (from torch>=1.9.0->open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/ff/74/a2e2be7fb83aaedec84f391f082cf765dfb635e7caa9b49065f73e4835d8/nvidia_cudnn_cu12-8.9.2.26-py3-none-manylinux1_x86_64.whl (731.7 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 731.7/731.7 MB 832.3 kB/s eta 0:00:00
Collecting nvidia-cublas-cu12==12.1.3.1 (from torch>=1.9.0->open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/37/6d/121efd7382d5b0284239f4ab1fc1590d86d34ed4a4a2fdb13b30ca8e5740/nvidia_cublas_cu12-12.1.3.1-py3-none-manylinux1_x86_64.whl (410.6 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 410.6/410.6 MB 1.8 MB/s eta 0:00:00
Collecting nvidia-cufft-cu12==11.0.2.54 (from torch>=1.9.0->open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/86/94/eb540db023ce1d162e7bea9f8f5aa781d57c65aed513c33ee9a5123ead4d/nvidia_cufft_cu12-11.0.2.54-py3-none-manylinux1_x86_64.whl (121.6 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 121.6/121.6 MB 2.5 MB/s eta 0:00:00
Collecting nvidia-curand-cu12==10.3.2.106 (from torch>=1.9.0->open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/44/31/4890b1c9abc496303412947fc7dcea3d14861720642b49e8ceed89636705/nvidia_curand_cu12-10.3.2.106-py3-none-manylinux1_x86_64.whl (56.5 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 56.5/56.5 MB 3.1 MB/s eta 0:00:00
Collecting nvidia-cusolver-cu12==11.4.5.107 (from torch>=1.9.0->open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/bc/1d/8de1e5c67099015c834315e333911273a8c6aaba78923dd1d1e25fc5f217/nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl (124.2 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 124.2/124.2 MB 2.3 MB/s eta 0:00:00
Collecting nvidia-cusparse-cu12==12.1.0.106 (from torch>=1.9.0->open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/65/5b/cfaeebf25cd9fdec14338ccb16f6b2c4c7fa9163aefcf057d86b9cc248bb/nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl (196.0 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 196.0/196.0 MB 3.4 MB/s eta 0:00:00
Collecting nvidia-nccl-cu12==2.20.5 (from torch>=1.9.0->open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/4b/2a/0a131f572aa09f741c30ccd45a8e56316e8be8dfc7bc19bf0ab7cfef7b19/nvidia_nccl_cu12-2.20.5-py3-none-manylinux2014_x86_64.whl (176.2 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 176.2/176.2 MB 1.9 MB/s eta 0:00:00
Collecting nvidia-nvtx-cu12==12.1.105 (from torch>=1.9.0->open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/da/d3/8057f0587683ed2fcd4dbfbdfdfa807b9160b809976099d36b8f60d08f03/nvidia_nvtx_cu12-12.1.105-py3-none-manylinux1_x86_64.whl (99 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 99.1/99.1 kB 1.8 MB/s eta 0:00:00
Collecting triton==2.3.0 (from torch>=1.9.0->open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/db/ee/8d50d44ed5b63677bb387f4ee67a7dbaaded0189b320ffe82685a6827728/triton-2.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (168.1 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 168.1/168.1 MB 1.8 MB/s eta 0:00:00
Collecting nvidia-nvjitlink-cu12 (from nvidia-cusolver-cu12==11.4.5.107->torch>=1.9.0->open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/ff/ff/847841bacfbefc97a00036e0fce5a0f086b640756dc38caea5e1bb002655/nvidia_nvjitlink_cu12-12.4.127-py3-none-manylinux2014_x86_64.whl (21.1 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 21.1/21.1 MB 4.7 MB/s eta 0:00:00
Requirement already satisfied: wcwidth<0.3.0,>=0.2.12 in /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages (from ftfy->open_clip_torch) (0.2.13)
Collecting packaging>=20.9 (from huggingface-hub->open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/49/df/1fceb2f8900f8639e278b056416d49134fb8d84c5942ffaa01ad34782422/packaging-24.0-py3-none-any.whl (53 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 53.5/53.5 kB 3.6 MB/s eta 0:00:00
Collecting pyyaml>=5.1 (from huggingface-hub->open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/29/61/bf33c6c85c55bc45a29eee3195848ff2d518d84735eb0e2d8cb42e0d285e/PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (705 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 705.5/705.5 kB 1.7 MB/s eta 0:00:00
Requirement already satisfied: requests in /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages (from huggingface-hub->open_clip_torch) (2.28.1)
Collecting safetensors (from timm->open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/8f/05/969e1a976b84283285181b00028cf73d78434b77a6627fc2a94194cca265/safetensors-0.4.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.2 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.2/1.2 MB 2.2 MB/s eta 0:00:00
INFO: pip is looking at multiple versions of torchvision to determine which version is compatible with other requirements. This could take a while.
Collecting torchvision (from open_clip_torch)
  Downloading https://pypi.tuna.tsinghua.edu.cn/packages/d4/7e/d41b771dbffa927b9cc37372b1e18c881348cd18a0e4ad73f2c6bdf56c0e/torchvision-0.18.0-cp310-cp310-manylinux1_x86_64.whl (7.0 MB)

du -sh /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages/
5.5G

pip install -r "requirements.txt" –prefer-binary -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install -r "requirements_versions.txt" –prefer-binary -i https://pypi.tuna.tsinghua.edu.cn/simple

du -sh /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages/
6.6G /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages/

pip install -r repositories/CodeFormer/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install -r repositories/BLIP/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install -r repositories/k-diffusion/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
pip install -r repositories/stable-diffusion-stability-ai/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

error: can’t find Rust compiler
ERROR: Failed building wheel for tokenizers
这个错误通常是由于缺少Rust编译器引起的,因为tokenizers库需要Rust编译器来构建。
apt-get install build-essential

git clone https://github.com/huggingface/tokenizers.git

安装rust

echo "export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static" >> ~/.bashrc
echo "export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup" >> ~/.bashrc
source ~/.bashrc
curl –proto ‘=https’ –tlsv1.2 -sSf https://sh.rustup.rs | sh

ust is installed now. Great!

To get started you may need to restart your current shell.
This would reload your PATH environment variable to include
Cargo's bin directory ($HOME/.cargo/bin).

To configure your current shell, you need to source
the corresponding env file under $HOME/.cargo.

This is usually done by running one of the following (note the leading DOT):
. "$HOME/.cargo/env"            # For sh/bash/zsh/ash/dash/pdksh
source "$HOME/.cargo/env.fish"  # For fish

pip install tokenizers

载入
source $HOME/.cargo/env

   SSL error: unknown error; class=Ssl (16)
  error: cargo metadata --manifest-path Cargo.toml --format-version 1 failed with code 101
  -- Output captured from stdout:

模型

下载基础模型放在 ./models/Stable-diffusion/
下载VAE模型放在 ./models/VAE/

先做一个共享目录
cd /workspace/common/
cp -ar /workspace/stable-diffusion-webui/models /workspace/common/
mv /workspace/stable-diffusion-webui/models /workspace/stable-diffusion-webui/models_org
ln -s /workspace/common/models/ /workspace/stable-diffusion-webui/models

退出docker,在宿主机复制现有模型到内部
docker cp Stable-diffusion/anything-v5-PrtRE.safetensors ub:/workspace/common/models/Stable-diffusion/

进docker
python -u ./launch.py –listen –port 5001 –use-cpu all –skip-torch-cuda-test –precision full –no-half –no-half-vae –api –skip-install

Python 3.10.10 (main, Mar 21 2023, 18:45:11) [GCC 11.2.0]
Version: 1.6.0
Commit hash: e5a634da06c62d72dbdc764b16c65ef3408aa588
Launching Web UI with arguments: --listen --port 5001 --use-cpu all --skip-torch-cuda-test --precision full --no-half --no-half-vae --api
WARNING:xformers:WARNING[XFORMERS]: xFormers can't load C++/CUDA extensions. xFormers was built for:
    PyTorch 2.3.0+cu121 with CUDA 1201 (you have 2.1.0+cpu)
    Python  3.10.14 (you have 3.10.10)
  Please reinstall xformers (see https://github.com/facebookresearch/xformers#installing-xformers)
  Memory-efficient attention, SwiGLU, sparse and more won't be available.
  Set XFORMERS_MORE_DETAILS=1 for more details
No module 'xformers'. Proceeding without it.
Warning: caught exception 'Torch not compiled with CUDA enabled', memory monitor disabled
Loading weights [7f96a1a9ca] from /workspace/stable-diffusion-webui-cpu/models/Stable-diffusion/anything-v5-PrtRE.safetensors
Creating model from config: /workspace/stable-diffusion-webui-cpu/configs/v1-inference.yaml
Running on local URL:  http://0.0.0.0:5001

To create a public link, set `share=True` in `launch()`.
Startup time: 5.7s (import torch: 2.4s, import gradio: 0.6s, setup paths: 0.7s, other imports: 0.3s, load scripts: 0.7s, create ui: 0.7s, gradio launch: 0.2s).
Applying attention optimization: InvokeAI... done.
Model loaded in 4.9s (load weights from disk: 0.8s, create model: 0.6s, apply weights to model: 2.7s, apply float(): 0.7s).
[W NNPACK.cpp:64] Could not initialize NNPACK! Reason: Unsupported hardware.

浏览器访问

http://127.0.0.1:5001
ersion: 1.6.0  •  python: 3.10.10  •  torch: 2.1.0+cpu  •  xformers: N/A  •  gradio: 3.41.2

报错

libGL.so.1

libGL.so.1: cannot open shared object file: No such file or directory

apt install mesa-utils

libgthread-2.0.so.0

libgthread-2.0.so.0: cannot open shared object file: No such file or directory

apt-get install libglib2.0-0

torchvision.transforms.functional_tenso

No module named ‘torchvision.transforms.functional_tensor’

pip list |grep torch

clip-anytorch             2.6.0
dctorch                   0.1.2
open-clip-torch           2.20.0
pytorch-lightning         1.9.4
torch                     2.3.0
torchaudio                2.1.0+cpu
torchdiffeq               0.2.3
torchmetrics              1.4.0
torchsde                  0.2.5
torchvision               0.18.0

重新安装支持cpu的torch版本
pip install torch==2.1.0 torchvision==0.16.0 torchaudio –index-url https://download.pytorch.org/whl/cpu

pip list |grep torch

clip-anytorch             2.6.0
dctorch                   0.1.2
open-clip-torch           2.20.0
pytorch-lightning         1.9.4
torch                     2.1.0+cpu
torchaudio                2.1.0+cpu
torchdiffeq               0.2.3
torchmetrics              1.4.0
torchsde                  0.2.5
torchvision               0.16.0+cpu

clip-vit-large-patch14

OSError: Can’t load tokenizer for ‘openai/clip-vit-large-patch14’. If you were trying to load it from ‘https://huggingface.co/models‘, make sure you don’t have a local directory with the same name. Otherwise, make sure ‘openai/clip-vit-large-patch14’ is the correct path to a directory containing all relevant files for a CLIPTokenizer tokenizer.

下载clip-vit-large-patch14 放到以下

tree /root/.cache/huggingface/hub/models--openai--clip-vit-large-patch14/
/root/.cache/huggingface/hub/models--openai--clip-vit-large-patch14/
|-- blobs
|-- refs
|   `-- main
`-- snapshots
    `-- 8d052a0f05efbaefbc9e8786ba291cfdf93e5bff
        |-- config.json
        |-- merges.txt
        |-- special_tokens_map.json
        |-- tokenizer_config.json
        `-- vocab.json

4 directories, 6 files

制作 完整版docker 镜像

docker ps

CONTAINER ID   IMAGE          COMMAND   CREATED        STATUS        PORTS     NAMES
0180e369be03   ubuntu:22.04   "bash"    19 hours ago   Up 19 hours             ub

docker commit -m "ubuntu:22.04,stable-diffusion,cpu" ub mysd:cpu

docker images

REPOSITORY                                              TAG                                   IMAGE ID       CREATED          SIZE
mysd                                                    cpu                                   93a4de4e2952   27 seconds ago   16GB

制作优化版docker 镜像

将python包和repositories 放到宿主机。
备份出repositories
docker exec -it ub ls /workspace
docker cp ub:/workspace/common/repositories /host/cpu_repositories
840M

备份出site-package

docker cp ub:/root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages/ /host/cpu_site-package
6G

进入镜像清理

docker exec -it ub bash
apt-get autoremove && apt-get clean && rm -rf /var/lib/apt/lists/*
rm -rf /root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages/
exit

镜像

docker commit -m "ubuntu:22.04,stable-diffusion,cpu" ub mysd:cpu-slim

docker images

REPOSITORY                                              TAG                                   IMAGE ID       CREATED          SIZE
mysd                                                    cpu-slim                              9e5113633411   19 seconds ago   10GB

启动文件

vi ./start.sh

/root/miniconda3/condabin/conda init  bash
conda activate python_3.10.10
export PATH="/root/miniconda3/envs/python_3.10.10/bin:$PATH"
git config --global --add safe.directory "*"
cd /workspace/stable-diffusion-webui
python -u ./launch.py --listen --port 5001 --use-cpu all --skip-torch-cuda-test --precision full --no-half --no-half-vae --api --skip-install

启动变量

h_dir=/host # host dir
h_mdir=/host/models # host models dir
c_dir=/workspace/stable-diffusion-webui # container dir
c_mdir=/workspace/stable-diffusion-webui/models # container dir

docker run -itd –network=host –name=cpusd \
-e COMMANDLINE_ARGS=’–use-cpu all –skip-torch-cuda-test –precision full –no-half –no-half-vae –api’ \
-e CONDA_DEFAULT_ENV=’python_3.10.10′ \
-v ${h_dir}/hub/:/root/.cache/huggingface/hub \
-v ${h_dir}/cpu_site-package:/root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages \
-v ${h_mdir}/:${c_mdir}/ \
-v ${h_dir}/style.csv:${c_dir}/style.csv \
-v ${h_dir}/outputs/:${c_dir}/outputs/ \
-v ${h_dir}/localizations/:${c_dir}/localizations/ \
-v ${h_dir}/configs/:${c_dir}/configs/ \
-v ${h_dir}/config_states/:${c_dir}/config_states/ \
-v ${h_dir}/cpu_repositories/:${c_dir}/repositories/ \
-v ${h_dir}/extensions/:${c_dir}/extensions/ \
-v ${h_dir}/extensions-builtin/:${c_dir}/extensions-builtin/ \
-v ${h_dir}/webui-user.sh:${c_dir}/webui-user.sh \
-v ${h_dir}/start.sh:${c_dir}/start.sh \
mysd:cpu-slim bash -c ‘source /root/.bashrc; conda init bash; conda activate python_3.10.10;conda info –envs;/workspace/stable-diffusion-webui/start.sh’

docker exec -it cpusd bash
docker logs -f cpusd

echo ‘docker start cpusd’ >> /etc/rc.local

sd-webui-bilingual-localization 双语对照翻译插件

cd /host/extensions
git clone https://github.com/journey-ad/sd-webui-bilingual-localization /host/extensions/sd-webui-bilingual-localization

settings->bilingual-localization
本地化文件 zh-Hans(stable)
同时请将"用户界面" – “本地化翻译”选项设置为“无”

保存并重启ui

制作使用dockerfile 镜像

cd /host/
从github下载准备好代码,并从zip转成tar,方便dockerfile解压
stable-diffusion-webui-cpu.tar
stable-diffusion-webui-1.6.0.tar

FROM ubuntu:22.04

LABEL maintainer="[email protected]" \
description="Ubuntu 22.04.4 LTS,miniconda3,Stable-Diffusion-webui" 

#docker build ./ --progress=plain -t sdw_cpu:1.0

ARG RUNUID="1000"
ARG RUNGID="1000"
ARG RUNUSER="www"
ARG RUNGROUP="website"
#ARG LANG="en_US.UTF-8"
ARG LANG="zh_CN.utf8"

ENV TZ=Asia/Shanghai
ENV RUNUID=${RUNUID}
ENV RUNGID=${RUNGID}
ENV RUNUSER=${RUNUSER}
ENV RUNGROUP=${RUNGROUP}
ENV LANG=${LANG}
ENV LC_ALL=${LANG}
ENV LANGUAGE=${LANG}

WORKDIR /workspace

USER root
RUN     groupadd -g $RUNUID $RUNGROUP && \
    useradd -u $RUNGID -G $RUNGROUP  -s /sbin/nologin $RUNUSER && \
    apt-get update && apt-get -y install --reinstall ca-certificates && \
    sed -i 's/http:\/\/.*ubuntu.com/https:\/\/mirrors.aliyun.com/g' /etc/apt/sources.list && \
    apt-get update && apt-get update && apt-get install -y sudo net-tools inetutils-ping procps curl wget vim telnet locales git zhcon  \
    fonts-wqy-microhei fonts-wqy-zenhei xfonts-wqy lrzsz unzip tree mesa-utils libglib2.0-0 && \
    apt-get autoremove && apt-get clean && rm -rf /var/lib/apt/lists/*  && \
    ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
    sed -i 's/# zh_CN.UTF-8 UTF-8/zh_CN.UTF-8 UTF-8/' /etc/locale.gen && locale-gen && \
    echo "$TZ" > /etc/timezone && echo "alias ll='ls -l'" >> /etc/profile && \
    cd /root && mkdir -p ~/miniconda3 && wget https://repo.anaconda.com/miniconda/Miniconda3-py310_22.11.1-1-Linux-x86_64.sh -O ~/miniconda.sh  && \
    bash ~/miniconda.sh -b -u -p ~/miniconda3 && ~/miniconda3/bin/conda init bash && . /root/.bashrc && \
    conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ && \
    conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ && \
    conda config --set show_channel_urls yes && conda create -n python_3.10.10 python=3.10.10 && conda activate python_3.10.10 && \
    pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple && \
    pip install --upgrade pip setuptools wheel && \
    cd /workspace && mkdir -p /workspace/common/{repositories,models}  
    #git clone https://github.com/openvinotoolkit/stable-diffusion-webui.git ./stable-diffusion-webui-cpu 
ADD stable-diffusion-webui-cpu.tar .
ADD stable-diffusion-webui-1.6.0.tar .
RUN  ln -s  stable-diffusion-webui-cpu  stable-diffusion-webui 

WORKDIR /workspace/stable-diffusion-webui 
EXPOSE 5001

#CMD ["/opt/bin/entry_point.sh"]
CMD ["tail","-f","/dev/null"]

docker build ./ –progress=plain -t sdw_cpu:1.0
镜像可以缩到1.6G

docker run -itd --network=host --name=cpusd \
-e COMMANDLINE_ARGS='--use-cpu all --skip-torch-cuda-test --precision full --no-half --no-half-vae  --api' \
-e CONDA_DEFAULT_ENV='python_3.10.10' \
-v ${h_dir}/hub:/root/.cache/huggingface/hub \
-v ${h_dir}/cpu_site-package:/root/miniconda3/envs/python_3.10.10/lib/python3.10/site-packages \
-v ${h_mdir}/:${c_mdir}/ \
-v ${h_dir}/style.csv:${c_dir}/style.csv \
-v ${h_dir}/outputs/:${c_dir}/outputs/ \
-v ${h_dir}/localizations/:${c_dir}/localizations/ \
-v ${h_dir}/configs/:${c_dir}/configs/ \
-v ${h_dir}/config.json:${c_dir}/config.json \
-v ${h_dir}/config_states/:${c_dir}/config_states/ \
-v ${h_dir}/cpu_repositories/:${c_dir}/repositories/ \
-v ${h_dir}/extensions/:${c_dir}/extensions/ \
-v ${h_dir}/extensions-builtin/:${c_dir}/extensions-builtin/ \
-v ${h_dir}/webui-user.sh:${c_dir}/webui-user.sh \
-v ${h_dir}/start.sh:${c_dir}/start.sh \
sdw_cpu:1.0  bash  -c 'source /root/.bashrc; conda init bash; conda activate python_3.10.10;conda info --envs;/workspace/stable-diffusion-webui/start.sh'

docker exec -it cpusd bash

Posted in AIGC, 技术.

Tagged with , , , , .