注意:

在 Oracle Linux 上运行 Kubernetes

简介

Kubernetes 是希腊的飞行员或头盔人员 - 换句话说,追随命令和引导船只走向其最终目标(而不是船长发出命令)。为此,Kubernetes 是一个开源的可扩展平台,用于部署、管理和扩展容器化应用。它使用多个命令行工具来实现此目的。此实验室使用名为 kubectl 的其中一个文件和 YAML 文件为部署应用程序的组织定义所需的属性,并了解在部署应用程序后如何设置和维护应用程序。

Kubernetes 集群上的所有部署都表示为对象。这些部署的对象使用基于文本的 YAML 文件提供部署到集群上的任何应用程序所需状态的详细信息。这些 YAML 文件可能描述以下内容:

这第三点虽然很重要,但是在不了解基础知识的情况下是复杂的。因此,我们暂且待会并在以后的教程中处理该主题。

此教程适用于在 Oracle Linux 上的紧凑型 Oracle Cloud Native Environment 中运行的 Kubernetes。对于管理生产部署所需的一切,其意图并不是“一站式服务”。相反,它引入了部署工作示例应用程序所需的技能。

目标

先决条件

具有以下配置的 Oracle Linux 8 或更高版本的系统:

设置实验室环境

注意:使用免费实验室环境时,请参见 Oracle Linux Lab Basics 了解连接和其他使用说明。

信息:免费实验室环境在提供的节点上部署 Oracle Cloud Native Environment,准备创建环境。此部署在启动后大约需要 8-10 分钟才能完成。因此,您可能希望在此运行期间退出,然后返回以完成练习。

  1. 如果尚未连接,请打开一个终端并通过 ssh 连接到 ocne-node01 系统。

    ssh oracle@<ip_address_of_ol_node>
    
  2. 确认环境已准备就绪。

    kubectl get pods -A
    

    输出示例:

    [oracle@ocne-node01 ~]$ kubectl get pods -A
    NAMESPACE                      NAME                                             READY   STATUS    RESTARTS   AGE
    externalip-validation-system   externalip-validation-webhook-7988bff847-8ws2v   1/1     Running   0          3m18s
    kube-system                    coredns-7cbc77dbc7-qxqth                         1/1     Running   0          3m18s
    kube-system                    coredns-7cbc77dbc7-r9bgj                         1/1     Running   0          3m18s
    kube-system                    etcd-ocne-node01                                 1/1     Running   0          3m37s
    kube-system                    kube-apiserver-ocne-node01                       1/1     Running   0          3m37s
    kube-system                    kube-controller-manager-ocne-node01              1/1     Running   0          3m37s
    kube-system                    kube-flannel-ds-vcwzn                            1/1     Running   0          3m18s
    kube-system                    kube-proxy-7lx59                                 1/1     Running   0          3m18s
    kube-system                    kube-scheduler-ocne-node01                       1/1     Running   0          3m37s
    kubernetes-dashboard           kubernetes-dashboard-5d5d4947b5-7pffh            1/1     Running   0          3m18s
    

在云池和请求详细信息上创建部署

在 Kubernetes 中,deployment 是指控制云池行为和特征的文件的技术术语。管理员使用部署来指示应用程序执行什么操作,Kubernetes 会执行任务来达到该状态。

这些示例使用的映像包含一个小 nginx Web 服务器,回显它通过 HTTP 标头接收的请求源 IP。

  1. 创建 echoserver 的部署。

    kubectl create deployment test --image=k8s.gcr.io/echoserver:1.4
    
  2. 列出集群中的所有 Pod。

    kubectl get pods
    

    输出示例:

    [oracle@ocne-node01 ~]$ kubectl get pods
    NAME                    READY   STATUS    RESTARTS   AGE
    test-6c486b6d76-467p7   1/1     Running   0          53s
    

    注:Pod 名称包含的后缀值在部署 Pod 时会有所不同。

  3. 使用 JSONPath 为变量指定 Pod 名称。

    TESTPOD=$(kubectl get pods -o jsonpath='{ $.items[*].metadata.name }')
    
  4. 测试变量赋值。

    kubectl get pods 命令还允许传递 pod 名称作为参数来仅显示该 Pod 的信息。

    kubectl get pods $TESTPOD
    
  5. 请求有关云池的选定信息。

    kubectl get pod $TESTPOD --output custom-columns=NAME:metadata.name,NODE_IP:status.hostIP,POD_IP:status.podIP
    

    输出示例:

    [oracle@ocne-node01 ~]$ kubectl get pod $TESTPOD --output custom-columns=NAME:metadata.name,NODE_IP:status.hostIP,POD_IP:status.podIP
    NAME                    NODE_IP      POD_IP
    test-6c486b6d76-467p7   10.0.0.140   10.244.0.7
    
  6. 获取 Pod 详细信息。

    kubectl describe pod $TESTPOD
    

    输出示例:

    [oracle@ocne-node01 ~]$ kubectl describe pod test-6c486b6d76-467p7
    Name:         test-6c486b6d76-467p7
    Namespace:    default
    Priority:     0
    Node:         ocne-node01/10.0.0.140
    Start Time:   Tue, 28 Jun 2022 19:21:27 +0000
    Labels:       app=test
                  pod-template-hash=6c486b6d76
    Annotations:  <none>
    Status:       Running
    IP:           10.244.0.7
    IPs:
      IP:           10.244.0.7
    Controlled By:  ReplicaSet/test-6c486b6d76
    Containers:
      echoserver:
        Container ID:   cri-o://5b7866a27722ec0998cd9fe74945fb82b4dd9ed4c5c80671d9e8aa239c7008a4
        Image:          k8s.gcr.io/echoserver:1.4
        Image ID:       k8s.gcr.io/echoserver@sha256:5d99aa1120524c801bc8c1a7077e8f5ec122ba16b6dda1a5d3826057f67b9bcb
        Port:           <none>
        Host Port:      <none>
        State:          Running
          Started:      Tue, 28 Jun 2022 19:21:30 +0000
        Ready:          True
        Restart Count:  0
        Environment:    <none>
        Mounts:
          /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-d67ph (ro)
    Conditions:
      Type              Status
      Initialized       True 
      Ready             True 
      ContainersReady   True 
      PodScheduled      True 
    Volumes:
      kube-api-access-d67ph:
        Type:                    Projected (a volume that contains injected data from multiple sources)
        TokenExpirationSeconds:  3607
        ConfigMapName:           kube-root-ca.crt
        ConfigMapOptional:       <nil>
        DownwardAPI:             true
    QoS Class:                   BestEffort
    Node-Selectors:              <none>
    Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                                 node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
    Events:
      Type    Reason     Age   From               Message
      ----    ------     ----  ----               -------
      Normal  Scheduled  21m   default-scheduler  Successfully assigned default/test-6c486b6d76-467p7 to ocne-node01
      Normal  Pulling    21m   kubelet            Pulling image "k8s.gcr.io/echoserver:1.4"
      Normal  Pulled     21m   kubelet            Successfully pulled image "k8s.gcr.io/echoserver:1.4" in 3.102843235s
      Normal  Created    21m   kubelet            Created container echoserver
      Normal  Started    21m   kubelet            Started container echoserver
    

使用 YAML 文件创建部署

使用 Kubernetes 部署清单定义了如何将应用程序部署到 Kubernetes 集群并提供对其他 Kubernetes 功能的访问,例如自我修复、可扩展性、版本控制和滚动更新。此实验室不具备 Kubernetes 中提供的更复杂功能。相反,它说明了如何使用非常基本的清单文件部署应用程序。

部署清单文件使用 JSON 或 YAML 写入。虽然可以使用 JSON,但由于 YAML 的灵活性、可读性以及包含描述性注释以阐明最终部署的各个方面,因此 YAML 更受欢迎。

运行部署时,Pod 将通过一系列声明性更新进行更新,以达到正在运行的应用程序的所需状态。

尽管 deployment.yaml 中的所有详细信息对于 Kubernetes 能够发出部署请求至关重要,但以下内容突出了一些更重要的部分:

有关这些其他字段的详细信息,请参阅上游部署文档。

  1. 创建部署文件。

    cat << 'EOF' | tee mydeployment.yaml > /dev/null
    apiVersion: apps/v1
    kind: Deployment
    metadata:
     name: echo1
    spec:
     selector:
       matchLabels: 
         app: echo1
     template:
       metadata:
         labels:
           app: echo1
       spec:
         containers:
         - name: echoserver
           image: k8s.gcr.io/echoserver:1.4
    EOF
    
  2. 使用部署清单文件在 Pod 上部署应用程序。

    kubectl apply -f mydeployment.yaml
    

    输出示例:

    [[oracle@ocne-node01 ~]$ kubectl apply -f mydeployment.yaml
    deployment.apps/echo1 created
    
  3. 列出由部署管理的 Pod。

    kubectl get pods -l app=echo1
    

    输出示例:

    [oracle@ocne-node01 ~]$ kubectl get pods -l app=echo1
    NAME                     READY   STATUS    RESTARTS   AGE
    echo1-7cbf6dfb96-4cgq7   1/1     Running   0          24s
    
    • -l--selector= 选项提供要过滤的选择器(标签查询)。此选项支持 ‘ = ’、‘ == ’和 ‘!= ’(例如 -l key1=value1,key2=value2

    注:提示 Pod 名称包含的后缀值在每次部署 Pod 时都会有所不同。

  4. 验证部署成功。

    kubectl get deploy echo1
    

    输出示例:

    [oracle@ocne-node01 ~]$ kubectl get deploy echo1
    NAME    READY   UP-TO-DATE   AVAILABLE   AGE
    echo1   1/1     1            1           16m
    
    • deploy 选项是 deployments 的快捷方式。kubectl 命令允许对其许多选项使用缩写语法。运行 kubectl --help 可获取更多详细信息。
  5. 返回部署的更多详细信息。

    kubectl describe deploy echo1
    

    输出示例:

    [oracle@ocne-node01 ~]$ kubectl describe deploy echo1
    Name:                   echo1
    Namespace:              default
    CreationTimestamp:      Tue, 28 Jun 2022 20:20:40 +0000
    Labels:                 <none>
    Annotations:            deployment.kubernetes.io/revision: 1
    Selector:               app=echo1
    Replicas:               1 desired | 1 updated | 1 total | 1 available | 0 unavailable
    StrategyType:           RollingUpdate
    MinReadySeconds:        0
    RollingUpdateStrategy:  25% max unavailable, 25% max surge
    Pod Template:
      Labels:  app=echo1
      Containers:
       echoserver:
        Image:        k8s.gcr.io/echoserver:1.4
        Port:         <none>
        Host Port:    <none>
        Environment:  <none>
        Mounts:       <none>
      Volumes:        <none>
    Conditions:
      Type           Status  Reason
      ----           ------  ------
      Available      True    MinimumReplicasAvailable
      Progressing    True    NewReplicaSetAvailable
    OldReplicaSets:  <none>
    NewReplicaSet:   echo1-7cbf6dfb96 (1/1 replicas created)
    Events:
      Type    Reason             Age   From                   Message
      ----    ------             ----  ----                   -------
      Normal  ScalingReplicaSet  23m   deployment-controller  Scaled up replica set echo1-7cbf6dfb96 to 1
    

使用 ClusterIP 服务

尽管将 echo1 部署成功部署到 Pod,但最终用户无法在内部或网络中访问该 Pod,这并没有什么用处。当服务向网络公开部署时,该访问便于访问。

默认 Kubernetes 服务类型为 ClusterIP。但是,您无法从 Internet 访问 ClusterIP 服务,但您可以使用 Kubernetes 代理。有关代理的更多信息,请参阅上游文档。

本部分公开了 echo1,并使用 Oracle Linux Pod 在集群中创建服务间通信,演示了应用程序前端和后端组件之间的通信。

  1. 获取节点列表。

    kubectl get nodes
    

    输出示例:

    [oracle@ocne-node01 ~]$ kubectl get nodes
    NAME          STATUS   ROLES    AGE     VERSION
    ocne-node01   Ready    <none>   4h27m   v1.22.8+1.el8
    

    节点是用于部署 Pod 的物理系统或虚拟机。

  2. 查询 kube-proxy 模式。

    iptables mode 中运行 kube-proxy 会导致发送到 ClusterIP 服务的数据包永远不是源 NAT。

    curl -w "\n" http://localhost:10249/proxyMode
    
    • kube-proxy 侦听运行它的节点上的端口 10249。
  3. 创建 ClusterIP 服务。

    kubectl expose deployment echo1 --name=clusterip-service --port=80 --target-port=8080
    
  4. 获取分配给群集的 IP 地址。

    kubectl get svc clusterip-service
    

    输出示例:

    [oracle@ocne-node01 ~]$ kubectl get svc clusterip-service
    NAME                TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
    clusterip-service   ClusterIP   10.108.107.54   <none>        80/TCP    13s
    

    请注意输出中的 CLUSTER-IP 地址。

  5. 在同一集群中创建用于访问 ClusterIP 服务的云池。

    kubectl run ol -it --image=oraclelinux:8 --restart=Never --rm
    

    此命令将在 interactive 模式下创建运行 Oracle Linux 8 容器的 Pod 并显示命令提示符。

    输出示例:

    [oracle@ocne-node01 ~]$ kubectl run ol -it --image=oraclelinux:8 --restart=Never --rm
    If you don't see a command prompt, try pressing enter.
    [root@ol /]#
    
  6. 获取 Oracle Linux 容器的 IP 地址。

    ip -br a
    

    输出示例:

    [root@ol /]# ip -br a
    lo               UNKNOWN        127.0.0.1/8 ::1/128 
    eth0@if12        UP             10.244.0.9/24 fe80::146f:2cff:fe73:b528/64
    
  7. echo1 中测试 nginx Web 服务器。

    curl -w "\n" <CLUSTER-IP_ADDRESS>
    

    使用上一个输出中的 CLUSTER-IP 地址。

    输出示例:

    [root@ol /]# curl -w "\n" 10.108.107.54
    CLIENT VALUES:
    client_address=10.244.0.9
    command=GET
    real path=/
    query=nil
    request_version=1.1
    request_uri=http://10.108.107.54:8080/
    
    SERVER VALUES:
    server_version=nginx: 1.10.0 - lua: 10001
    
    HEADERS RECEIVED:
    accept=*/*
    host=10.108.107.54
    user-agent=curl/7.61.1
    BODY:
    -no body in request-
    

    输出显示来自 Oracle Linux 的请求,并由 ClusterIP 服务使用 echo1 部署进行处理。

  8. 退出容器。

    exit
    

    输出示例:

    [root@ol /]# exit
    exit
    pod "ol" deleted
    

将 NodePort 服务与 YAML 文件结合使用

以前,echo1 部署使用 kubectl expose 命令公开,并在内部使用 ClusterIP 访问。现在,我们将使用 NodePort 服务,该服务是开发人员通过网络在外部访问 echo1 的方法。

NodePort 服务在所有节点上打开特定端口,并将任何流量转发到该端口到服务。

注意标准做法不建议出于以下原因对生产系统使用 NodePort

  1. 定义服务文件。

    cat << 'EOF' | tee myservice.yaml > /dev/null
    apiVersion: v1
    kind: Service
    metadata:
      name: echo1-nodeport
      namespace: default
    spec:
      ipFamilies:
      - IPv4
      ipFamilyPolicy: SingleStack
      ports:
      - nodePort: 32387
        port: 80
        protocol: TCP
        targetPort: 8080
      selector:
        app: echo1
      sessionAffinity: None
      type: NodePort
    status:
      loadBalancer: {}
    EOF
    
    • type:- 使服务可用于外部客户机的网络请求。有效值包括:nodePort、LooadBalancer。
    • nodePort:- 用于访问服务的外部端口。
    • port:- 在群集中公开的端口号。
    • targetPort:- 容器正在侦听的端口。
  2. 创建服务。

    kubectl apply -f myservice.yaml
    

    输出示例:

    [oracle@ocne-node01 ~]$ kubectl apply -f myservice.yaml 
    service/echo1 created
    

    注:在同一 YAML 文件中通常具有部署和服务定义,以简化应用程序的管理。在这些步骤中使用单独的文件仅用于培训。将它们组合到单个文件中时,使用 --- YAML 语法进行分隔。

  3. 显示 Kubernetes 如何存储新创建的服务。

    kubectl get service echo1-nodeport -o yaml
    

    输出示例:

    [oracle@ocne-node01 ~]$ kubectl get service echo1-nodeport -o yaml
    apiVersion: v1
    kind: Service
    metadata:
      annotations:
        kubectl.kubernetes.io/last-applied-configuration: |
          {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"echo1-nodeport","namespace":"default"},"spec":{"ipFamilies":["IPv4"],"ipFamilyPolicy":"SingleStack","ports":[{"nodePort":32387,"port":80,"protocol":"TCP","targetPort":8080}],"selector":{"app":"echo1"},"sessionAffinity":"None","type":"NodePort"},"status":{"loadBalancer":{}}}
      creationTimestamp: "2022-06-29T00:14:30Z"
      name: echo1-nodeport
      namespace: default
      resourceVersion: "6242"
      uid: 3171dda6-05b8-45b8-a0ba-457eab6e4f71
    spec:
      clusterIP: 10.100.17.53
      clusterIPs:
      - 10.100.17.53
      externalTrafficPolicy: Cluster
      internalTrafficPolicy: Cluster
      ipFamilies:
      - IPv4
      ipFamilyPolicy: SingleStack
      ports:
      - nodePort: 32387
        port: 80
        protocol: TCP
        targetPort: 8080
      selector:
        app: echo1
      sessionAffinity: None
      type: NodePort
    status:
      loadBalancer: {}
    
  4. 描述 Pods 服务。

    kubectl describe svc echo1-nodeport
    

    输出示例:

    [oracle@ocne-node01 ~]$ kubectl describe svc echo1-nodeport
    Name:                     echo1-nodeport
    Namespace:                default
    Labels:                   <none>
    Annotations:              <none>
    Selector:                 app=echo1
    Type:                     NodePort
    IP Family Policy:         SingleStack
    IP Families:              IPv4
    IP:                       10.100.17.53
    IPs:                      10.100.17.53
    Port:                     <unset>  80/TCP
    TargetPort:               8080/TCP
    NodePort:                 <unset>  32387/TCP
    Endpoints:                10.244.0.7:8080
    Session Affinity:         None
    External Traffic Policy:  Cluster
    Events:                   <none>
    
  5. 获取对象端点。

    端点跟踪服务向其发送流量的 Pod 的 IP 地址。

    kubectl get endpoints echo1-nodeport
    

    输出示例:

    [oracle@ocne-node01 ~]$ kubectl get endpoints echo1-nodeport
    NAME             ENDPOINTS         AGE
    echo1-nodeport   10.244.0.7:8080   8m39s
    
  6. 列出运行应用程序的 Pod。

    kubectl get pods --output=wide
    

    输出示例:

    [oracle@ocne-node01 ~]$ kubectl get pods -o wide
    NAME                     READY   STATUS    RESTARTS   AGE   IP           NODE          NOMINATED NODE   READINESS GATES
    echo1-7cbf6dfb96-mlds4   1/1     Running   0          80m   10.244.0.7   ocne-node01   <none>           <none>
    test-6c486b6d76-v4htj    1/1     Running   0          83m   10.244.0.6   ocne-node01   <none>           <none>
    

    此列表中针对 echo1IP 地址应与上一步中针对端点显示的值匹配,即在指定节点上运行的 Pod 的 IP 地址。

  7. 列出服务。

    kubectl get svc -o wide
    

    输出示例:

    [oracle@ocne-node01 ~]$ kubectl get svc -o wide
    NAME                TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE   SELECTOR
    clusterip-service   ClusterIP   10.107.31.75   <none>        80/TCP         78m   app=echo1
    echo1-nodeport      NodePort    10.100.17.53   <none>        80:32387/TCP   10m   app=echo1
    kubernetes          ClusterIP   10.96.0.1      <none>        443/TCP        88m   <none>
    

    此命令使用 -o wide 的替代选项,而不是 --output=wide

    请注意 NodePort,对于 echo1-nodeport 服务,它设置为 32387

  8. 获取节点的 IP 地址。

    免费实验室环境在单个节点 ocne-node01 上运行。

    ip -br a
    

    在免费实验室环境中,IP 地址应返回分配给接口 ens3 的实例专用 IP 地址 10.0.0.140

  9. 使用 JSONPath 为 NodePort 分配变量。

    NODEPORT=$(kubectl get -o jsonpath="{.spec.ports[0].nodePort}" services echo1-nodeport)
    
  10. 使用 JSONPath 将节点 IP 分配给变量。

    NODES=$(kubectl get nodes -o jsonpath='{ $.items[*].status.addresses[?(@.type=="InternalIP")].address }')
    
  11. 创建防火墙规则。

    此规则允许 node:nodeport 上的流量,其中 node 是运行 Pod 的系统或虚拟机的主机 IP 地址。

    sudo firewall-cmd --permanent --add-port=$NODEPORT/tcp
    sudo firewall-cmd --reload
    

    --reload 之后,twalld 守护进程重新加载其配置,其中包括 iptables。由于 kube-proxy 依赖于 iptables,因此服务响应出现延迟。

  12. 使用节点地址和节点端口验证应用程序。

    curl -s $NODES:$NODEPORT
    

    输出示例:

    [oracle@ocne-node01 ~]$ curl -s $NODES:NODEPORT
    CLIENT VALUES:
    client_address=10.244.0.1
    command=GET
    real path=/
    query=nil
    request_version=1.1
    request_uri=http://10.0.0.140:8080/
    
    SERVER VALUES:
    server_version=nginx: 1.10.0 - lua: 10001
    
    HEADERS RECEIVED:
    accept=*/*
    host=10.0.0.140:32387
    user-agent=curl/7.61.1
    BODY:
    

    输出显示从本地节点通过 NodePort 服务、通过 kube-proxy 以及到运行 echo1 部署的 Pod 的请求。

    注:如果输出显示为挂起,这是由于之前重新装入防火墙。键入 Ctrl-C 并重试。

删除部署和服务

完成服务或部署后,将其从 Kubernetes 中删除。

  1. 删除服务。

    kubectl delete svc clusterip-service echo1-nodeport
    
  2. 删除部署。

    kubectl delete deployments echo1
    kubectl delete deploy test
    

可以单独或分组删除对象。有关详细信息,请查看 Kubernetes 参考手册

摘要

此实验室只提供了有关使用云原生编排器(例如 Kubernetes)功能简介的最简要介绍,该功能使用 Kubernetes 向任何组织提供了使用 Kubernetes 管理容器部署的功能。这些练习提供了第一步,说明使用 Kubernetes 提供的灵活性很长的旅程。

详细信息

更多学习资源

浏览 docs.oracle.com/learn 上的其他实验室,或者在 Oracle Learning YouTube 频道上访问更多免费学习内容。此外,请访问 education.oracle.com/learning-explorer 以成为 Oracle Learning Explorer。

有关产品文档,请访问 Oracle 帮助中心