注意:
- 此教程在 Oracle 提供的免费实验室环境中提供。
- 它使用 Oracle Cloud Infrastructure 身份证明、租户和区间的示例值。完成练习后,将这些值替换为特定于云环境的值。
在 Oracle Linux 上运行 Kubernetes
简介
Kubernetes 是希腊的飞行员或头盔人员 - 换句话说,追随命令和引导船只走向其最终目标(而不是船长发出命令)。为此,Kubernetes 是一个开源的可扩展平台,用于部署、管理和扩展容器化应用。它使用多个命令行工具来实现此目的。此实验室使用名为 kubectl 的其中一个文件和 YAML 文件为部署应用程序的组织定义所需的属性,并了解在部署应用程序后如何设置和维护应用程序。
Kubernetes 集群上的所有部署都表示为对象。这些部署的对象使用基于文本的 YAML 文件提供部署到集群上的任何应用程序所需状态的详细信息。这些 YAML 文件可能描述以下内容:
- 要在哪些节点上运行的容器化应用程序
- 应用程序所需的资源的详细信息
- 详细介绍这些应用程序如何维护其状态的任何策略,例如重新启动策略、升级策略等。
这第三点虽然很重要,但是在不了解基础知识的情况下是复杂的。因此,我们暂且待会并在以后的教程中处理该主题。
此教程适用于在 Oracle Linux 上的紧凑型 Oracle Cloud Native Environment 中运行的 Kubernetes。对于管理生产部署所需的一切,其意图并不是“一站式服务”。相反,它引入了部署工作示例应用程序所需的技能。
目标
- 分析不同的 Kubernetes 组件,例如云池、部署和服务
- 分析不同的 Kubernetes 对象
- 部署和测试示例项目
先决条件
具有以下配置的 Oracle Linux 8 或更高版本的系统:
- 具有
sudo特权的非 root 用户 - 已安装并配置 Oracle Cloud Native Environment
设置实验室环境
注意:使用免费实验室环境时,请参见 Oracle Linux Lab Basics 了解连接和其他使用说明。
信息:免费实验室环境在提供的节点上部署 Oracle Cloud Native Environment,准备创建环境。此部署在启动后大约需要 8-10 分钟才能完成。因此,您可能希望在此运行期间退出,然后返回以完成练习。
-
如果尚未连接,请打开一个终端并通过 ssh 连接到 ocne-node01 系统。
ssh oracle@<ip_address_of_ol_node> -
确认环境已准备就绪。
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。
-
创建 echoserver 的部署。
kubectl create deployment test --image=k8s.gcr.io/echoserver:1.4 -
列出集群中的所有 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 时会有所不同。
-
使用 JSONPath 为变量指定 Pod 名称。
TESTPOD=$(kubectl get pods -o jsonpath='{ $.items[*].metadata.name }') -
测试变量赋值。
kubectl get pods命令还允许传递 pod 名称作为参数来仅显示该 Pod 的信息。kubectl get pods $TESTPOD -
请求有关云池的选定信息。
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 -
获取 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 能够发出部署请求至关重要,但以下内容突出了一些更重要的部分:
- apiVersion 字段指定要使用的 Kubernetes API 版本。如果使用的是最新版本的 Kubernetes,请将其设置为 apps/v1。
- 在此实例中,种类字段通知 Kubernetes 引用一种称为部署的对象。
- 元数据部分用于概述部署名称和关联标签的详细信息
- .spec 部分可能是任何部署清单文件的最关键部分。从这里向下的任何东西都与部署云池有关。.spec.template 部分下的任何内容都描述 Kubernetes 用于管理部署的 Pod 模板(在本示例中为单个容器)。
- 本示例中未使用的其他字段包括 .spec.replicas 字段(指示 Kubernetes 要部署的 Pod 副本数)和 .spec.strategy 字段(指示 Kubernetes 如何对部署执行更新)。
有关这些其他字段的详细信息,请参阅上游部署文档。
-
创建部署文件。
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 -
使用部署清单文件在 Pod 上部署应用程序。
kubectl apply -f mydeployment.yaml输出示例:
[[oracle@ocne-node01 ~]$ kubectl apply -f mydeployment.yaml deployment.apps/echo1 created -
列出由部署管理的 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 时都会有所不同。
-
验证部署成功。
kubectl get deploy echo1输出示例:
[oracle@ocne-node01 ~]$ kubectl get deploy echo1 NAME READY UP-TO-DATE AVAILABLE AGE echo1 1/1 1 1 16mdeploy选项是deployments的快捷方式。kubectl命令允许对其许多选项使用缩写语法。运行kubectl --help可获取更多详细信息。
-
返回部署的更多详细信息。
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 在集群中创建服务间通信,演示了应用程序前端和后端组件之间的通信。
-
获取节点列表。
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 的物理系统或虚拟机。
-
查询 kube-proxy 模式。
在 iptables mode 中运行 kube-proxy 会导致发送到 ClusterIP 服务的数据包永远不是源 NAT。
curl -w "\n" http://localhost:10249/proxyMode- kube-proxy 侦听运行它的节点上的端口 10249。
-
创建 ClusterIP 服务。
kubectl expose deployment echo1 --name=clusterip-service --port=80 --target-port=8080 -
获取分配给群集的 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地址。 -
在同一集群中创建用于访问 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 /]# -
获取 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 -
在 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 部署进行处理。
-
退出容器。
exit输出示例:
[root@ol /]# exit exit pod "ol" deleted
将 NodePort 服务与 YAML 文件结合使用
以前,echo1 部署使用 kubectl expose 命令公开,并在内部使用 ClusterIP 访问。现在,我们将使用 NodePort 服务,该服务是开发人员通过网络在外部访问 echo1 的方法。
NodePort 服务在所有节点上打开特定端口,并将任何流量转发到该端口到服务。
注意标准做法不建议出于以下原因对生产系统使用 NodePort:
- 部署的每个 Service 需要不同的端口
- 节点需要公开可用 - 不建议这样做。
- 节点之间没有负载平衡(在多节点 Kubernetes 集群中)
-
定义服务文件。
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:- 容器正在侦听的端口。
-
创建服务。
kubectl apply -f myservice.yaml输出示例:
[oracle@ocne-node01 ~]$ kubectl apply -f myservice.yaml service/echo1 created注:在同一 YAML 文件中通常具有部署和服务定义,以简化应用程序的管理。在这些步骤中使用单独的文件仅用于培训。将它们组合到单个文件中时,使用
---YAML 语法进行分隔。 -
显示 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: {} -
描述 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> -
获取对象端点。
端点跟踪服务向其发送流量的 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 -
列出运行应用程序的 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>此列表中针对 echo1 的 IP 地址应与上一步中针对端点显示的值匹配,即在指定节点上运行的 Pod 的 IP 地址。
-
列出服务。
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。
-
获取节点的 IP 地址。
免费实验室环境在单个节点 ocne-node01 上运行。
ip -br a在免费实验室环境中,IP 地址应返回分配给接口 ens3 的实例专用 IP 地址 10.0.0.140。
-
使用 JSONPath 为 NodePort 分配变量。
NODEPORT=$(kubectl get -o jsonpath="{.spec.ports[0].nodePort}" services echo1-nodeport) -
使用 JSONPath 将节点 IP 分配给变量。
NODES=$(kubectl get nodes -o jsonpath='{ $.items[*].status.addresses[?(@.type=="InternalIP")].address }') -
创建防火墙规则。
此规则允许
node:nodeport上的流量,其中node是运行 Pod 的系统或虚拟机的主机 IP 地址。sudo firewall-cmd --permanent --add-port=$NODEPORT/tcp sudo firewall-cmd --reload在
--reload之后,twalld 守护进程重新加载其配置,其中包括iptables。由于 kube-proxy 依赖于iptables,因此服务响应出现延迟。 -
使用节点地址和节点端口验证应用程序。
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 中删除。
-
删除服务。
kubectl delete svc clusterip-service echo1-nodeport -
删除部署。
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 帮助中心。