Guía práctica de KubeKey para actualizar las versiones menores de Kubernetes

Autor: Habilidades de operación y mantenimiento

Prefacio

Puntos de conocimiento

  • Clasificación: nivel de entrada
  • Cómo KubeKey actualiza las versiones menores de Kubernetes
  • Preparación y verificación de la actualización de Kubernetes
  • Preguntas frecuentes sobre KubeKey y la actualización de Kubernetes

Configuración real del servidor (arquitectura réplica 1:1 de un entorno de producción a pequeña escala, la configuración es ligeramente diferente)

nombre de la CPU IP UPC Memoria disco del sistema disco de datos usar
k8s-master-1 192.168.9.91 4 dieciséis 40 100 KubeSphere/k8s-master
k8s-master-2 192.168.9.92 4 dieciséis 40 100 KubeSphere/k8s-master
k8s-master-3 192.168.9.93 4 dieciséis 40 100 KubeSphere/k8s-master
k8s-trabajador-1 192.168.9.95 8 dieciséis 40 100 k8s-trabajador/CI
k8s-trabajador-2 192.168.9.96 8 dieciséis 40 100 trabajador-k8s
k8s-trabajador-3 192.168.9.97 8 dieciséis 40 100 trabajador-k8s
k8s-almacenamiento-1 192.168.9.81 4 dieciséis 40 100/100/100/100/100 ElasticSearch/GlusterFS/Ceph-Rook/Longhorn/NFS/
k8s-almacenamiento-2 192.168.9.82 4 dieciséis 40 100/100/100/100 ElasticSearch/GlusterFS/Ceph-Rook/Longhorn/
k8s-almacenamiento-3 192.168.9.83 4 dieciséis 40 100/100/100/100 ElasticSearch/GlusterFS/Ceph-Rook/Longhorn/
registro 192.168.9.80 4 8 40 100 Sonatype Nexus 3
total 10 52 152 400 2000

El entorno de combate real implica información sobre la versión del software.

  • Sistema operativo: CentOS 7.9 x86_64
  • KubeSphere: v3.4.1
  • Kubernetes: v1.24.14 a v1.26.5
  • En contenedor: 1.6.4
  • Clave de Kube: v3.0.13

1. Introducción

En el último número, completamos la actualización de la versión del parche real de KubeSphere y Kubernetes . En este número, aprenderemos cómo usar KubeKey para implementar la actualización de la versión menor de Kubernetes.

Este número no cubre las actualizaciones de versiones menores de KubeSphere. Los lectores que lo necesiten pueden consultar la documentación de actualización oficial para la versión correspondiente .

Con respecto a la actualización de versiones menores, mis consideraciones personales son las siguientes:

  • Ya sea KubeSphere o Kubernetes, no actualice a menos que sea necesario (el riesgo es alto y hay demasiados factores incontrolables. Incluso si se realizan suficientes pruebas de verificación con anticipación, ¿quién puede garantizar que no habrá accidentes en las actualizaciones de producción?)
  • Kubernetes no debe actualizarse en su lugar a menos que sea necesario. Se recomienda adoptar la solución de "crear una nueva versión del clúster + migrar aplicaciones comerciales" o una actualización azul-verde.
  • Las actualizaciones in situ deben limitarse a dos versiones menores tanto como sea posible, y se debe realizar suficiente investigación y verificación (como la compatibilidad de recursos causada por diferentes versiones, diferentes API, radio de explosión de actualizaciones fallidas, etc.)
  • La actualización entre versiones de KubeSphere es más complicada: cuantos más complementos adicionales estén habilitados, más componentes y precios intermedios estarán involucrados, y más puntos de verificación deben considerarse para la actualización.

KubeKey admite dos escenarios de actualización : clúster todo en uno y clúster de múltiples nodos. Este artículo solo demuestra el escenario de actualización del clúster de múltiples nodos. Para el clúster todo en uno, consulte la guía de actualización oficial .

El proceso de actualización de las versiones menores de KubeSphere y Kubernetes es el mismo que el proceso de actualización de la versión del parche, por lo que no lo describiré en detalle aquí. Consulte más arriba para obtener más detalles.

2. Mejora los requisitos previos para el combate real.

En la última edición, completamos la actualización de Kubernetes v1.24.12 a v1.24.14. En esta edición, actualizaremos Kubernetes v1.24.14 a v1.26.5 según el mismo entorno.

Al mismo tiempo, para simular escenarios comerciales reales, continuamos creando algunos recursos de prueba. Antes de la verificación, también debemos registrar información clave sobre el clúster actual.

2.1 Entorno de clúster

  • KubeSphere v3.4.1, con la mayoría de los complementos habilitados
  • Instalar el clúster de Kubernetes v1.24.14
  • Conéctese al almacenamiento NFS u otro almacenamiento como almacenamiento persistente (este artículo utiliza NFS para el entorno de prueba)

2.2 Ver información actual del entorno del clúster

La información actual del entorno del clúster que se ve a continuación no es suficiente. Solo analiza algunos recursos representativos. Debe haber componentes e información que se han ignorado.

  • Ver toda la información del nodo
[root@k8s-master-1 ~]# kubectl get nodes -o wide
NAME           STATUS   ROLES                  AGE     VERSION    INTERNAL-IP    EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION                CONTAINER-RUNTIME
k8s-master-1   Ready    control-plane          6d21h   v1.24.14   192.168.9.91   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4
k8s-master-2   Ready    control-plane,worker   6d21h   v1.24.14   192.168.9.92   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4
k8s-master-3   Ready    control-plane,worker   6d21h   v1.24.14   192.168.9.93   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4
k8s-worker-1   Ready    worker                 6d21h   v1.24.14   192.168.9.95   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4
k8s-worker-2   Ready    worker                 6d21h   v1.24.14   192.168.9.96   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4
k8s-worker-3   Ready    worker                 6d19h   v1.24.14   192.168.9.97   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4
  • Vea las imágenes utilizadas por todas las implementaciones para facilitar la comparación después de la actualización ( solo para registros, de poca importancia práctica, los resultados no incluyen los componentes principales de Kubernetes )
# 受限于篇幅,输出结果略,请自己保存结果
kubectl get deploy -A -o wide
  • Ver recursos de Kubernetes ( limitados por espacio, los resultados del pod no se muestran )
[root@k8s-master-1 ~]# kubectl get pods,deployment,sts,ds -o wide -n kube-system
NAME                                          READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS                     IMAGES                                                                    SELECTOR
deployment.apps/calico-kube-controllers       1/1     1            1           6d21h   calico-kube-controllers        registry.cn-beijing.aliyuncs.com/kubesphereio/kube-controllers:v3.26.1    k8s-app=calico-kube-controllers
deployment.apps/coredns                       2/2     2            2           6d21h   coredns                        registry.cn-beijing.aliyuncs.com/kubesphereio/coredns:1.8.6               k8s-app=kube-dns
deployment.apps/metrics-server                1/1     1            1           6d21h   metrics-server                 registry.cn-beijing.aliyuncs.com/kubesphereio/metrics-server:v0.4.2       k8s-app=metrics-server
deployment.apps/openebs-localpv-provisioner   1/1     1            1           6d21h   openebs-provisioner-hostpath   registry.cn-beijing.aliyuncs.com/kubesphereio/provisioner-localpv:3.3.0   name=openebs-localpv-provisioner,openebs.io/component-name=openebs-localpv-provisioner

NAME                                   READY   AGE     CONTAINERS            IMAGES
statefulset.apps/snapshot-controller   1/1     6d21h   snapshot-controller   registry.cn-beijing.aliyuncs.com/kubesphereio/snapshot-controller:v4.0.0

NAME                          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE     CONTAINERS    IMAGES                                                                     SELECTOR
daemonset.apps/calico-node    6         6         6       6            6           kubernetes.io/os=linux   6d21h   calico-node   registry.cn-beijing.aliyuncs.com/kubesphereio/node:v3.26.1                 k8s-app=calico-node
daemonset.apps/kube-proxy     6         6         6       6            6           kubernetes.io/os=linux   6d21h   kube-proxy    registry.cn-beijing.aliyuncs.com/kubesphereio/kube-proxy:v1.24.14          k8s-app=kube-proxy
daemonset.apps/nodelocaldns   6         6         6       6            6           <none>                   6d21h   node-cache    registry.cn-beijing.aliyuncs.com/kubesphereio/k8s-dns-node-cache:1.15.12   k8s-app=nodelocaldns
  • Ver la imagen utilizada por los nodos Master y Worker actuales
# Master
[root@k8s-master-1 ~]#  crictl images | grep v1.24.14
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-apiserver            v1.24.14            b651b48a617a5       34.3MB
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-controller-manager   v1.24.14            d40212fa9cf04       31.5MB
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-proxy                v1.24.14            e57c0d007d1ef       39.7MB
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-scheduler            v1.24.14            19bf7b80c50e5       15.8MB

# Worker
[root@k8s-worker-1 ~]# crictl images | grep v1.24.14
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-proxy                      v1.24.14                       e57c0d007d1ef       39.7MB
  • Verifique los archivos binarios del componente principal de Kubernetes ( registre y compare si hay actualizaciones )
[root@k8s-master-1 ~]# ll /usr/local/bin/
total 352448
-rwxr-xr-x 1 root root  65770992 Dec  4 15:09 calicoctl
-rwxr-xr-x 1 root root  23847904 Nov 29 13:50 etcd
-rwxr-xr-x 1 kube root  17620576 Nov 29 13:50 etcdctl
-rwxr-xr-x 1 root root  46182400 Dec  4 15:09 helm
-rwxr-xr-x 1 root root  44748800 Dec  4 15:09 kubeadm
-rwxr-xr-x 1 root root  46080000 Dec  4 15:09 kubectl
-rwxr-xr-x 1 root root 116646168 Dec  4 15:09 kubelet
drwxr-xr-x 2 kube root        71 Nov 29 13:51 kube-scripts

2.3 Crear recursos de verificación de pruebas

  • Crear espacio de nombres de pruebaupgrade-test
kubectl create ns upgrade-test
  • Cree un archivo de recursos de prueba ( use StatefulSet para crear rápidamente el volumen de prueba correspondiente ), use la imagen nginx:latest para crear un negocio de prueba de 6 copias (incluido PVC) y cada copia se distribuye en un nodo trabajador.vi nginx-test.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: test-nginx
  namespace: upgrade-test
spec:
  selector:
    matchLabels:
      app: nginx
  serviceName: "nginx"
  replicas: 6
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: nfs-volume
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: nfs-volume
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "nfs-sc"
      resources:
        requests:
          storage: 1Gi
  • Crear recursos de prueba
kubectl apply -f nginx-test.yaml
  • Escribir archivo de página de inicio de índice
for id in $(seq 0 1 5);do kubectl exec -it test-nginx-$id -n upgrade-test  -- sh -c "echo I test-nginx-$id > /usr/share/nginx/html/index.html";done
  • Ver recursos de prueba
# 查看 Pod(每个节点一个副本)
[root@k8s-master-1 ~]# kubectl get pods -o wide -n upgrade-test
NAME           READY   STATUS    RESTARTS   AGE     IP              NODE           NOMINATED NODE   READINESS GATES
test-nginx-0   1/1     Running   0          8m32s   10.233.80.77    k8s-master-1   <none>           <none>
test-nginx-1   1/1     Running   0          8m10s   10.233.96.33    k8s-master-3   <none>           <none>
test-nginx-2   1/1     Running   0          7m47s   10.233.85.99    k8s-master-2   <none>           <none>
test-nginx-3   1/1     Running   0          7m25s   10.233.87.104   k8s-worker-3   <none>           <none>
test-nginx-4   1/1     Running   0          7m3s    10.233.88.180   k8s-worker-1   <none>           <none>
test-nginx-5   1/1     Running   0          6m41s   10.233.74.129   k8s-worker-2   <none>           <none>

# 查看 PVC
[root@k8s-master-1 ~]# kubectl get pvc -o wide -n upgrade-test
NAME                      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE     VOLUMEMODE
nfs-volume-test-nginx-0   Bound    pvc-e7875a9c-2736-4b32-aa29-b338959bb133   1Gi        RWO            nfs-sc         8m52s   Filesystem
nfs-volume-test-nginx-1   Bound    pvc-8bd760a8-64f9-40e9-947f-917b6308c146   1Gi        RWO            nfs-sc         8m30s   Filesystem
nfs-volume-test-nginx-2   Bound    pvc-afb47509-c249-4892-91ad-da0f69e33495   1Gi        RWO            nfs-sc         8m7s    Filesystem
nfs-volume-test-nginx-3   Bound    pvc-e6cf5935-2852-4ef6-af3d-a06458bceb49   1Gi        RWO            nfs-sc         7m45s   Filesystem
nfs-volume-test-nginx-4   Bound    pvc-7d176238-8106-4cc9-b49d-fceb25242aee   1Gi        RWO            nfs-sc         7m23s   Filesystem
nfs-volume-test-nginx-5   Bound    pvc-dc35e933-0b3c-4fb9-9736-78528d26ce6f   1Gi        RWO            nfs-sc         7m1s    Filesystem

# 查看 index.html
[root@k8s-master-1 ~]# for id in $(seq 0 1 5);do kubectl exec -it test-nginx-$id -n upgrade-test  -- cat /usr/share/nginx/html/index.html;done
I test-nginx-0
I test-nginx-1
I test-nginx-2
I test-nginx-3
I test-nginx-4
I test-nginx-5

2.4 Observar el estado del clúster y del negocio durante la actualización

Las observaciones de este artículo no son necesariamente completas ni suficientes, por lo que es necesario complementarlas en función del entorno real al realizar pruebas de verificación de actualización reales. No es conveniente tomar capturas de pantalla del proceso de observación, por lo que se pide a los lectores que observen por sí mismos.

  • Observar el estado del nodo del clúster
 watch kubectl get nodes
  • Observe el estado de los recursos del espacio de nombres de prueba (centrese en si RESTARTS cambia)
watch kubectl get pods -o wide -n upgrade-test
  • Haga ping a la IP empresarial simulada (busque un Pod aleatoriamente)
ping 10.233.80.77
  • IP empresarial simulada por curl (encontrar aleatoriamente un Pod, diferente al probado por Ping)
watch curl 10.233.88.180
  • Observe la situación de montaje del disco empresarial simulado (la escritura no se verifica, concéntrese en observar si los resultados de salida tienen almacenamiento nfs)
watch kubectl exec -it test-nginx-3 -n upgrade-test  -- df -h

3. Descargue KubeKey

Antes de actualizar el clúster, ejecute el siguiente comando para descargar la última versión o la versión especificada de KubeKey.

export KKZONE=cn
curl -sfL https://get-kk.kubesphere.io | VERSION=v3.0.13 sh -

4. Genere el archivo de configuración de implementación del clúster

4.1 Utilice KubeKey para generar archivos de configuración

Antes de actualizar, debe preparar los archivos de implementación del clúster. Primero , se recomienda utilizar KubeKey para implementar los archivos de configuración utilizados al implementar los clústeres de KubeSphere y Kubernetes.

Si se pierde la configuración utilizada durante la implementación, puede ejecutar el siguiente comando para crear un sample.yamlarchivo de configuración basado en el clúster existente ( se muestra el enfoque de este artículo ).

./kk create config --from-cluster

Observación:

Este artículo asume que kubeconfig está ubicado en ~/.kube/config. Puedes --kubeconfigmodificar esto a través de la bandera.

Los resultados reales de la ejecución del comando son los siguientes:

[root@k8s-master-1 kubekey]# ./kk create config --from-cluster
Notice: /root/kubekey/sample.yaml has been created. Some parameters need to be filled in by yourself, please complete it.

Archivo de configuración generadosample.yaml

apiVersion: kubekey.kubesphere.io/v1alpha2
kind: Cluster
metadata:
  name: sample
spec:
  hosts:
  ##You should complete the ssh information of the hosts
  - {name: k8s-master-1, address: 192.168.9.91, internalAddress: 192.168.9.91}
  - {name: k8s-master-2, address: 192.168.9.92, internalAddress: 192.168.9.92}
  - {name: k8s-master-3, address: 192.168.9.93, internalAddress: 192.168.9.93}
  - {name: k8s-worker-1, address: 192.168.9.95, internalAddress: 192.168.9.95}
  - {name: k8s-worker-2, address: 192.168.9.96, internalAddress: 192.168.9.96}
  - {name: k8s-worker-3, address: 192.168.9.97, internalAddress: 192.168.9.97}
  roleGroups:
    etcd:
    - SHOULD_BE_REPLACED
    master:
    worker:
    - k8s-master-1
    - k8s-master-2
    - k8s-master-3
    - k8s-worker-1
    - k8s-worker-2
    - k8s-worker-3
  controlPlaneEndpoint:
    ##Internal loadbalancer for apiservers
    #internalLoadbalancer: haproxy

    ##If the external loadbalancer was used, 'address' should be set to loadbalancer's ip.
    domain: lb.opsman.top
    address: ""
    port: 6443
  kubernetes:
    version: v1.24.14
    clusterName: opsman.top
    proxyMode: ipvs
    masqueradeAll: false
    maxPods: 110
    nodeCidrMaskSize: 24
  network:
    plugin: calico
    kubePodsCIDR: 10.233.64.0/18
    kubeServiceCIDR: 10.233.0.0/18
  registry:
    privateRegistry: ""

4.2 Modificar la plantilla del archivo de configuración

Modifique el archivo de acuerdo con la configuración real del clúster sample.yaml. Asegúrese de modificar los siguientes campos correctamente.

  • hosts: Información básica sobre su host (nombre de host y dirección IP) e información sobre el uso de SSH para conectarse al host ( modificaciones clave, debe agregar el nombre de usuario y la contraseña de SSH ).
  • roleGroups.etcd: nodo etcd ( modificaciones clave ).
  • roleGroups.master: nodo maestro ( la modificación de clave, no generada de forma predeterminada, debe agregarse manualmente, de lo contrario se informará un error, consulte la pregunta frecuente 1 ), nota: el nombre de este campo de parámetro en el archivo de configuración generado durante la implementación es roleGroups.control-plane.
  • roleGroups.worker:nodo trabajador ( verificar modificación ).
  • controlPlaneEndpoint: información del equilibrador de carga ( opcional ).
  • kubernetes.containerManager: modifique el tiempo de ejecución del contenedor ( obligatorio, no generado de forma predeterminada, debe agregarse manualmente, de lo contrario se informará un error; consulte la pregunta frecuente 2 ).
  • registry: Información del servicio espejo ( opcional ).

Contenido del archivo modificado:

apiVersion: kubekey.kubesphere.io/v1alpha2
kind: Cluster
metadata:
  name: sample
spec:
  hosts:
  ##You should complete the ssh information of the hosts
  - {name: k8s-master-1, address: 192.168.9.91, internalAddress: 192.168.9.91, user: root, password: "P@88w0rd"}
  - {name: k8s-master-2, address: 192.168.9.92, internalAddress: 192.168.9.92, user: root, password: "P@88w0rd"}
  - {name: k8s-master-3, address: 192.168.9.93, internalAddress: 192.168.9.93, user: root, password: "P@88w0rd"}
  - {name: k8s-worker-1, address: 192.168.9.95, internalAddress: 192.168.9.95, user: root, password: "P@88w0rd"}
  - {name: k8s-worker-2, address: 192.168.9.96, internalAddress: 192.168.9.96, user: root, password: "P@88w0rd"}
  - {name: k8s-worker-3, address: 192.168.9.97, internalAddress: 192.168.9.97, user: root, password: "P@88w0rd"}
  roleGroups:
    etcd:
    - k8s-master-1
    - k8s-master-2
    - k8s-master-3
    master:
    - k8s-master-1
    - k8s-master-2
    - k8s-master-3
    worker:
    - k8s-master-1
    - k8s-master-2
    - k8s-master-3
    - k8s-worker-1
    - k8s-worker-2
    - k8s-worker-3
  controlPlaneEndpoint:
    ##Internal loadbalancer for apiservers
    internalLoadbalancer: haproxy

    ##If the external loadbalancer was used, 'address' should be set to loadbalancer's ip.
    domain: lb.opsman.top
    address: ""
    port: 6443
  kubernetes:
    version: v1.24.12
    clusterName: opsman.top
    proxyMode: ipvs
    masqueradeAll: false
    maxPods: 110
    nodeCidrMaskSize: 24
    containerManager: containerd
  network:
    plugin: calico
    kubePodsCIDR: 10.233.64.0/18
    kubeServiceCIDR: 10.233.0.0/18
  registry:
    privateRegistry: ""

5. Actualizar Kubernetes

5.1 Actualizar Kubernetes

Ejecute el siguiente comando para actualizar Kubernetes de v1.24.14 a v1.26.5 .

export KKZONE=cn
./kk upgrade --with-kubernetes v1.26.5 -f sample.yaml

Los resultados después de la ejecución son los siguientes ( ingrese cuando se le solicite yescontinuar ):

[root@k8s-master-1 kubekey]# ./kk upgrade --with-kubernetes v1.26.5 -f sample.yaml


 _   __      _          _   __
| | / /     | |        | | / /
| |/ / _   _| |__   ___| |/ /  ___ _   _
|    \| | | | '_ \ / _ \    \ / _ \ | | |
| |\  \ |_| | |_) |  __/ |\  \  __/ |_| |
\_| \_/\__,_|_.__/ \___\_| \_/\___|\__, |
                                    __/ |
                                   |___/

09:26:43 CST [GreetingsModule] Greetings
09:26:43 CST message: [k8s-worker-3]
Greetings, KubeKey!
09:26:44 CST message: [k8s-master-3]
Greetings, KubeKey!
09:26:44 CST message: [k8s-master-1]
Greetings, KubeKey!
09:26:44 CST message: [k8s-worker-1]
Greetings, KubeKey!
09:26:44 CST message: [k8s-master-2]
Greetings, KubeKey!
09:26:44 CST message: [k8s-worker-2]
Greetings, KubeKey!
09:26:44 CST success: [k8s-worker-3]
09:26:44 CST success: [k8s-master-3]
09:26:44 CST success: [k8s-master-1]
09:26:44 CST success: [k8s-worker-1]
09:26:44 CST success: [k8s-master-2]
09:26:44 CST success: [k8s-worker-2]
09:26:44 CST [NodePreCheckModule] A pre-check on nodes
09:26:45 CST success: [k8s-worker-2]
09:26:45 CST success: [k8s-worker-3]
09:26:45 CST success: [k8s-master-2]
09:26:45 CST success: [k8s-worker-1]
09:26:45 CST success: [k8s-master-3]
09:26:45 CST success: [k8s-master-1]
09:26:45 CST [ClusterPreCheckModule] Get KubeConfig file
09:26:45 CST skipped: [k8s-master-3]
09:26:45 CST skipped: [k8s-master-2]
09:26:45 CST success: [k8s-master-1]
09:26:45 CST [ClusterPreCheckModule] Get all nodes Kubernetes version
09:26:45 CST success: [k8s-worker-2]
09:26:45 CST success: [k8s-worker-3]
09:26:45 CST success: [k8s-worker-1]
09:26:45 CST success: [k8s-master-2]
09:26:45 CST success: [k8s-master-3]
09:26:45 CST success: [k8s-master-1]
09:26:45 CST [ClusterPreCheckModule] Calculate min Kubernetes version
09:26:45 CST skipped: [k8s-master-3]
09:26:45 CST success: [k8s-master-1]
09:26:45 CST skipped: [k8s-master-2]
09:26:45 CST [ClusterPreCheckModule] Check desired Kubernetes version
09:26:45 CST skipped: [k8s-master-3]
09:26:45 CST success: [k8s-master-1]
09:26:45 CST skipped: [k8s-master-2]
09:26:45 CST [ClusterPreCheckModule] Check KubeSphere version
09:26:45 CST skipped: [k8s-master-3]
09:26:45 CST skipped: [k8s-master-2]
09:26:45 CST success: [k8s-master-1]
09:26:45 CST [ClusterPreCheckModule] Check dependency matrix for KubeSphere and Kubernetes
09:26:45 CST skipped: [k8s-master-3]
09:26:45 CST skipped: [k8s-master-2]
09:26:45 CST success: [k8s-master-1]
09:26:45 CST [ClusterPreCheckModule] Get kubernetes nodes status
09:26:45 CST skipped: [k8s-master-3]
09:26:45 CST skipped: [k8s-master-2]
09:26:45 CST success: [k8s-master-1]
09:26:45 CST [UpgradeConfirmModule] Display confirmation form
+--------------+------+------+---------+----------+-------+-------+---------+-----------+--------+--------+------------+------------+-------------+------------------+--------------+
| name         | sudo | curl | openssl | ebtables | socat | ipset | ipvsadm | conntrack | chrony | docker | containerd | nfs client | ceph client | glusterfs client | time         |
+--------------+------+------+---------+----------+-------+-------+---------+-----------+--------+--------+------------+------------+-------------+------------------+--------------+
| k8s-master-1 | y    | y    | y       | y        | y     | y     | y       | y         | y      |        | v1.6.4     | y          |             |                  | CST 09:26:45 |
| k8s-master-2 | y    | y    | y       | y        | y     | y     | y       | y         | y      |        | v1.6.4     | y          |             |                  | CST 09:26:45 |
| k8s-master-3 | y    | y    | y       | y        | y     | y     | y       | y         | y      |        | v1.6.4     | y          |             |                  | CST 09:26:45 |
| k8s-worker-1 | y    | y    | y       | y        | y     | y     | y       | y         | y      |        | v1.6.4     | y          |             |                  | CST 09:26:45 |
| k8s-worker-2 | y    | y    | y       | y        | y     | y     | y       | y         | y      |        | v1.6.4     | y          |             |                  | CST 09:26:45 |
| k8s-worker-3 | y    | y    | y       | y        | y     | y     | y       | y         | y      |        | v1.6.4     | y          |             |                  | CST 09:26:45 |
+--------------+------+------+---------+----------+-------+-------+---------+-----------+--------+--------+------------+------------+-------------+------------------+--------------+

Cluster nodes status:
NAME           STATUS   ROLES                  AGE     VERSION    INTERNAL-IP    EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION                CONTAINER-RUNTIME
k8s-master-1   Ready    control-plane          6d21h   v1.24.14   192.168.9.91   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4
k8s-master-2   Ready    control-plane,worker   6d21h   v1.24.14   192.168.9.92   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4
k8s-master-3   Ready    control-plane,worker   6d21h   v1.24.14   192.168.9.93   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4
k8s-worker-1   Ready    worker                 6d21h   v1.24.14   192.168.9.95   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4
k8s-worker-2   Ready    worker                 6d21h   v1.24.14   192.168.9.96   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4
k8s-worker-3   Ready    worker                 6d19h   v1.24.14   192.168.9.97   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4

Upgrade Confirmation:
kubernetes version: v1.24.14 to v1.26.5

Continue upgrading cluster? [yes/no]:

Nota: Se confirma la información de actualización y Kubernetes solicita actualizar de v1.24.14 a v1.26.5.

Después de hacer clic en "Sí", el resultado final de la ejecución de la versión abreviada es el siguiente:

09:47:18 CST [ProgressiveUpgradeModule 2/2] Set current k8s version
09:47:18 CST skipped: [LocalHost]
09:47:18 CST [ChownModule] Chown user $HOME/.kube dir
09:47:19 CST success: [k8s-worker-3]
09:47:19 CST success: [k8s-worker-1]
09:47:19 CST success: [k8s-worker-2]
09:47:19 CST success: [k8s-master-1]
09:47:19 CST success: [k8s-master-2]
09:47:19 CST success: [k8s-master-3]
09:47:19 CST Pipeline[UpgradeClusterPipeline] execute successfully

Nota: Debido a limitaciones de espacio, no puedo pegar los resultados completos de la ejecución. Sin embargo, recomiendo encarecidamente que los lectores guarden y analicen cuidadosamente el registro del proceso de actualización para tener una comprensión más profunda del proceso de actualización de Kubekey para Kubernetes. Estos archivos de registro brindan información importante sobre los eventos que ocurrieron durante el proceso de actualización y pueden ayudarlo a comprender mejor todo el proceso de actualización y los problemas que pueda encontrar, y solucionarlos si es necesario.

5.2 Instrucciones de observación para el proceso de actualización

Al observar los resultados de la tarea durante el proceso de actualización, hay algunos puntos a tener en cuenta:

  • Los nodos Master y Worker se actualizarán uno por uno (Master tarda aproximadamente 2 minutos, Worker tarda aproximadamente 1 minuto). Durante el proceso de actualización, cuando el nodo Master ejecuta el comando kubectl, la API no se puede conectar.
[root@k8s-master-1 ~]# kubectl get nodes
The connection to the server lb.opsman.top:6443 was refused - did you specify the right host or port?

ilustrar:

La aparición de este fenómeno no significa que la API de Kubernetes no tenga alta disponibilidad, de hecho, tiene pseudo-alta disponibilidad.

Principalmente porque el HAProxy de equilibrio de carga integrado implementado por KubeKey solo actúa en el nodo trabajador y el nodo maestro solo se conectará al kube-apiserver local ( por lo tanto, también muestra que es mejor crear un equilibrio de carga autoconstruido). si es posible ).

# Master 节点
[root@k8s-master-1 ~]# ss -ntlup | grep 6443
tcp    LISTEN     0      32768  [::]:6443               [::]:*                   users:(("kube-apiserver",pid=11789,fd=7))


# Worker 节点
[root@k8s-worker-1 ~]# ss -ntlup | grep 6443
tcp    LISTEN     0      4000   127.0.0.1:6443                  *:*                   users:(("haproxy",pid=53535,fd=7))
  • El servicio empresarial Nginx probado no se interrumpió ( no se encontraron anomalías en ping, curl y df ).
  • Secuencia de actualización del componente principal de Kubernetes: primero actualice a v1.25.10 , luego actualice a v1.26.5 ( de acuerdo con los requisitos del diseño de Kubekey y las diferencias de actualización de la versión menor de Kubernetes )
  • Las imágenes kube-apiserver, kube-controller-manager, kube-proxy y kube-scheduler se actualizaron de v1.24.14 a v1.25.10 y luego a v1.26.5 .

Lista de software binario descargado al actualizar a v1.25.10** (la descripción en negrita ha cambiado)**:

  • kubeadm v1.25.10

  • kubelet v1.25.10

  • kubectl v1.25.10

  • timón v3.9.0

  • cubo v1.2.0

  • crictl v1.24.0

  • etcétera v3.4.13

  • en contenedor 1.6.4

  • ejecutar v1.1.1

  • calicoctl v3.26.1

Lista de software binario descargado al actualizar a v1.26.5** (la descripción en negrita ha cambiado)**:

  • kubeadm v1.26.5

  • kubelet v1.26.5

  • kubectl v1.26.5

  • Nada más cambió

Lista de imágenes involucradas en el proceso de actualización** (las descripciones en negrita han cambiado)**:

  • calico/cni:v3.26.1
  • Controladores calico/kube:v3.26.1
  • calico/nodo:v3.26.1
  • calico/pod2daemon-flexvol:v3.26.1
  • núcleos/corazones:1.9.3
  • kubesphere/k8s-dns-node-cache:1.15.12
  • kubesphere/kube-apserver:v1.25.10
  • kubesphere/kube-apserver:v1.26.5
  • kubesphere/kube-controller-manager:v1.25.10
  • kubesphere/kube-controller-manager:v1.26.5
  • kubesphere/kube-proxy:v1.25.10
  • kubesphere/kube-proxy:v1.26.5
  • kubesphere/kube-scheduler:v1.25.10
  • kubesphere/kube-scheduler:v1.26.5
  • kubesphere/pausa: 3.8
  • biblioteca/haproxy:2.3

Lista de imágenes principales de todos los nodos después de la actualización (verifique el orden de las versiones actualizadas):

# Master 命令有筛选,去掉了 v1.24.12 和重复的 docker.io 开通的镜像
[root@k8s-master-1 ~]# crictl images | grep v1.2[4-6] | grep -v "24.12"| grep -v docker.io | sort
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-apiserver            v1.24.14            b651b48a617a5       34.3MB
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-apiserver            v1.25.10            4aafc4b1604b9       34.4MB
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-apiserver            v1.26.5             25c2ecde661fc       35.5MB
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-controller-manager   v1.24.14            d40212fa9cf04       31.5MB
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-controller-manager   v1.25.10            e446ea5ea9b1b       31.5MB
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-controller-manager   v1.26.5             a7403c147a516       32.4MB
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-proxy                v1.24.14            e57c0d007d1ef       39.7MB
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-proxy                v1.25.10            0cb798db55ff2       20.3MB
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-proxy                v1.26.5             08440588500d7       21.5MB
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-scheduler            v1.24.14            19bf7b80c50e5       15.8MB
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-scheduler            v1.25.10            de3c37c13188f       16MB
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-scheduler            v1.26.5             200132c1d91ab       17.7MB

# Worker
[root@k8s-worker-1 ~]# crictl images | grep v1.2[4-6] | grep -v "24.12"| grep -v docker.io | sort
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-proxy                      v1.24.14                       e57c0d007d1ef       39.7MB
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-proxy                      v1.25.10                       0cb798db55ff2       20.3MB
registry.cn-beijing.aliyuncs.com/kubesphereio/kube-proxy                      v1.26.5                        08440588500d7       21.5MB

5.3 Verificación después de la actualización de Kubernetes

  • Ver versión de Nodos ( VERSIÓN actualizada a v1.26.5 )
[root@k8s-master-1 ~]# kubectl get nodes -o wide
NAME           STATUS   ROLES                  AGE     VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION                CONTAINER-RUNTIME
k8s-master-1   Ready    control-plane          6d22h   v1.26.5   192.168.9.91   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4
k8s-master-2   Ready    control-plane,worker   6d22h   v1.26.5   192.168.9.92   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4
k8s-master-3   Ready    control-plane,worker   6d22h   v1.26.5   192.168.9.93   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4
k8s-worker-1   Ready    worker                 6d22h   v1.26.5   192.168.9.95   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4
k8s-worker-2   Ready    worker                 6d22h   v1.26.5   192.168.9.96   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4
k8s-worker-3   Ready    worker                 6d20h   v1.26.5   192.168.9.97   <none>        CentOS Linux 7 (Core)   5.4.261-1.el7.elrepo.x86_64   containerd://1.6.4
  • Ver recursos de Kubernetes ( debido a limitaciones de espacio, los resultados del pod no se muestran, pero todos los cambios reales están en el pod )
[root@k8s-master-1 kubekey]# kubectl get pod,deployment,sts,ds -o wide -n kube-system
NAME                                          READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS                     IMAGES                                                                    SELECTOR
deployment.apps/calico-kube-controllers       1/1     1            1           6d22h   calico-kube-controllers        registry.cn-beijing.aliyuncs.com/kubesphereio/kube-controllers:v3.26.1    k8s-app=calico-kube-controllers
deployment.apps/coredns                       2/2     2            2           6d22h   coredns                        registry.cn-beijing.aliyuncs.com/kubesphereio/coredns:1.8.6               k8s-app=kube-dns
deployment.apps/metrics-server                1/1     1            1           6d22h   metrics-server                 registry.cn-beijing.aliyuncs.com/kubesphereio/metrics-server:v0.4.2       k8s-app=metrics-server
deployment.apps/openebs-localpv-provisioner   1/1     1            1           6d22h   openebs-provisioner-hostpath   registry.cn-beijing.aliyuncs.com/kubesphereio/provisioner-localpv:3.3.0   name=openebs-localpv-provisioner,openebs.io/component-name=openebs-localpv-provisioner

NAME                                   READY   AGE     CONTAINERS            IMAGES
statefulset.apps/snapshot-controller   1/1     6d22h   snapshot-controller   registry.cn-beijing.aliyuncs.com/kubesphereio/snapshot-controller:v4.0.0

NAME                          DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE     CONTAINERS    IMAGES                                                             SELECTOR
daemonset.apps/calico-node    6         6         6       6            6           kubernetes.io/os=linux   6d22h   calico-node   registry.cn-beijing.aliyuncs.com/kubesphereio/node:v3.26.1         k8s-app=calico-node
daemonset.apps/kube-proxy     6         6         6       6            6           kubernetes.io/os=linux   6d22h   kube-proxy    registry.cn-beijing.aliyuncs.com/kubesphereio/kube-proxy:v1.26.5   k8s-app=kube-proxy
daemonset.apps/nodelocaldns   6         6         6       6            6           <none>                   6d22h   node-cache    kubesphere/k8s-dns-node-cache:1.15.12                              k8s-app=nodelocaldns
  • Ver el archivo binario ( compare los resultados antes de la actualización para verificar si los componentes han cambiado )
[root@k8s-master-1 ~]# ll /usr/local/bin/
total 360880
-rwxr-xr-x 1 root root  65770992 Dec  6 09:41 calicoctl
-rwxr-xr-x 1 root root  23847904 Nov 29 13:50 etcd
-rwxr-xr-x 1 kube root  17620576 Nov 29 13:50 etcdctl
-rwxr-xr-x 1 root root  46182400 Dec  6 09:41 helm
-rwxr-xr-x 1 root root  46788608 Dec  6 09:41 kubeadm
-rwxr-xr-x 1 root root  48046080 Dec  6 09:41 kubectl
-rwxr-xr-x 1 root root 121277432 Dec  6 09:41 kubelet
drwxr-xr-x 2 kube root        71 Nov 29 13:51 kube-scripts

Nota: Excepto etcd y etcdctl, todo lo demás se ha actualizado, lo que indica que etcd no está dentro del alcance de las actualizaciones de componentes.

  • Crear recursos de prueba
kubectl create deployment nginx-upgrade-test --image=nginx:latest --replicas=6 -n upgrade-test

Nota: Esta prueba es relativamente simple y se recomienda realizar pruebas más suficientes para entornos de producción .

  • Ver los recursos de prueba creados
# 查看 Deployment
[root@k8s-master-1 ~]# kubectl get deployment -n upgrade-test -o wide
NAME                 READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES         SELECTOR
nginx-upgrade-test   6/6     6            6           13s   nginx        nginx:latest   app=nginx-upgrade-test

# 查看 Pod
[root@k8s-master-1 ~]# kubectl get deployment,pod -n upgrade-test -o wide
NAME                                 READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES         SELECTOR
deployment.apps/nginx-upgrade-test   6/6     6            6           56s   nginx        nginx:latest   app=nginx-upgrade-test

NAME                                      READY   STATUS    RESTARTS   AGE   IP              NODE           NOMINATED NODE   READINESS GATES
pod/nginx-upgrade-test-7b668447c4-cglmh   1/1     Running   0          56s   10.233.80.85    k8s-master-1   <none>           <none>
pod/nginx-upgrade-test-7b668447c4-cmzqx   1/1     Running   0          56s   10.233.88.181   k8s-worker-1   <none>           <none>
pod/nginx-upgrade-test-7b668447c4-ggnjg   1/1     Running   0          56s   10.233.87.106   k8s-worker-3   <none>           <none>
pod/nginx-upgrade-test-7b668447c4-hh8h4   1/1     Running   0          56s   10.233.96.38    k8s-master-3   <none>           <none>
pod/nginx-upgrade-test-7b668447c4-hs7n7   1/1     Running   0          56s   10.233.74.130   k8s-worker-2   <none>           <none>
pod/nginx-upgrade-test-7b668447c4-s6wps   1/1     Running   0          56s   10.233.85.102   k8s-master-2   <none>           <none>
pod/test-nginx-0                          1/1     Running   0          85m   10.233.80.77    k8s-master-1   <none>           <none>
pod/test-nginx-1                          1/1     Running   0          85m   10.233.96.33    k8s-master-3   <none>           <none>
pod/test-nginx-2                          1/1     Running   0          84m   10.233.85.99    k8s-master-2   <none>           <none>
pod/test-nginx-3                          1/1     Running   0          84m   10.233.87.104   k8s-worker-3   <none>           <none>
pod/test-nginx-4                          1/1     Running   0          83m   10.233.88.180   k8s-worker-1   <none>           <none>
pod/test-nginx-5                          1/1     Running   0          83m   10.233.74.129   k8s-worker-2   <none>           <none>
  • Reconstruir pods existentes ( no verificado, se debe verificar la actualización del entorno de producción para evitar problemas de compatibilidad entre versiones )
  • Verifique el estado del clúster en la consola de administración de KubeSphere

componentes-de-clústeres-ksp-v124-a-v126

descripción general del clúster de monitorización de clústeres ksp-v124 a v126

Después de una serie de operaciones, utilizamos KubeKey con éxito para completar la actualización y la verificación de prueba de la versión menor de Kubernetes. En este proceso, hemos pasado por muchos vínculos clave, incluida la preparación del entorno de combate real, la implementación de actualizaciones y las pruebas y verificación. Al final, logramos el objetivo de actualizar la versión y verificamos que el sistema actualizado pudiera ( básicamente ) funcionar normalmente.

6. Preguntas frecuentes

Pregunta 1

  • Mensaje de error
[root@k8s-master-1 kubekey]# ./kk upgrade --with-kubesphere v3.4.1 -f sample.yaml
14:00:54 CST [FATA] The number of master/control-plane cannot be 0
  • solución

Modifique el archivo de implementación del clúster sample.yamly complételo correctamente roleGroups.master: información del nodo maestro

Pregunta 2

  • Mensaje de error
Continue upgrading cluster? [yes/no]: yes
14:07:02 CST success: [LocalHost]
14:07:02 CST [SetUpgradePlanModule 1/2] Set upgrade plan
14:07:02 CST success: [LocalHost]
14:07:02 CST [SetUpgradePlanModule 1/2] Generate kubeadm config
14:07:02 CST message: [k8s-master-1]
Failed to get container runtime cgroup driver.: Failed to exec command: sudo -E /bin/bash -c "docker info | grep 'Cgroup Driver'"
/bin/bash: docker: command not found: Process exited with status 1
14:07:02 CST retry: [k8s-master-1]
14:07:07 CST message: [k8s-master-1]
Failed to get container runtime cgroup driver.: Failed to exec command: sudo -E /bin/bash -c "docker info | grep 'Cgroup Driver'"
/bin/bash: docker: command not found: Process exited with status 1
14:07:07 CST retry: [k8s-master-1]
14:07:12 CST message: [k8s-master-1]
Failed to get container runtime cgroup driver.: Failed to exec command: sudo -E /bin/bash -c "docker info | grep 'Cgroup Driver'"
/bin/bash: docker: command not found: Process exited with status 1
14:07:12 CST skipped: [k8s-master-3]
14:07:12 CST skipped: [k8s-master-2]
14:07:12 CST failed: [k8s-master-1]
error: Pipeline[UpgradeClusterPipeline] execute failed: Module[SetUpgradePlanModule 1/2] exec failed:
failed: [k8s-master-1] [GenerateKubeadmConfig] exec failed after 3 retries: Failed to get container runtime cgroup driver.: Failed to exec command: sudo -E /bin/bash -c "docker info | grep 'Cgroup Driver'"
/bin/bash: docker: command not found: Process exited with status 1
  • solución

Modifique el archivo de implementación del clúster sample.yamly complételo correctamente kubernetes.containerManager: containerd. Docker se utiliza de forma predeterminada.

7. Resumen

Este artículo demuestra a través de combates reales el proceso detallado de actualización de las versiones menores de Kubernetes de KubeSphere y los clústeres de Kubernetes implementados por KubeKey, así como los problemas encontrados durante el proceso de actualización y las soluciones correspondientes. Al mismo tiempo, también explica qué verificaciones se requieren antes y después de la actualización para garantizar el éxito de la actualización del sistema.

Usar KubeKey para actualizar KubeSphere y Kubernetes y completar la verificación de prueba es una tarea compleja e importante. A través de esta actualización real, verificamos la viabilidad técnica, actualizamos y optimizamos el sistema y mejoramos el rendimiento y la seguridad del sistema. Al mismo tiempo, también hemos acumulado valiosas experiencias y lecciones que sirven de referencia para futuras actualizaciones del entorno de producción.

En resumen, el texto completo incluye principalmente los siguientes contenidos:

  • Preparación mejorada para el entorno de combate real.
  • Preparación de actualización de Kubernetes y monitoreo del proceso de actualización
  • Actualice Kubernetes usando KubeKey
  • Verificación posterior a la actualización de Kubernetes

El contenido práctico proporcionado en este artículo se puede aplicar directamente a entornos de prueba y desarrollo. Al mismo tiempo, también tiene cierto valor de referencia para el entorno de producción. Sin embargo, tenga cuidado de no aplicar esto directamente a un entorno de producción.

¡Este artículo es publicado por OpenWrite, un blog que publica varios artículos !

IntelliJ IDEA 2023.3 y JetBrains Family Bucket actualización anual de la versión principal nuevo concepto "programación defensiva": conviértase en un trabajo estable GitHub.com ejecuta más de 1200 hosts MySQL, ¿cómo actualizar sin problemas a 8.0? El equipo Web3 de Stephen Chow lanzará una aplicación independiente el próximo mes ¿ Se eliminará Firefox? Visual Studio Code 1.85 lanzado, ventana flotante Yu Chengdong: Huawei lanzará productos disruptivos el próximo año y reescribirá la historia de la industria. La CISA de EE. UU. recomienda abandonar C/C++ para eliminar las vulnerabilidades de seguridad de la memoria. TIOBE Diciembre: Se espera que C# se convierta en la programación idioma del año Un artículo escrito por Lei Jun hace 30 años: "Principio y diseño del sistema experto de determinación de virus informáticos"
{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/4197945/blog/10320906
Recomendado
Clasificación