Kubernetes
1.1 应用部署方式演变
在部署应用程序的方式上,主要经历了三个时代:
-
传统部署:互联网早期,会直接将应用程序部署在物理机上
优点:简单,不需要其它技术的参与
缺点:不能为应用程序定义资源使用边界,很难合理地分配计算资源,而且程序之间容易产生影响
-
虚拟化部署:可以在一台物理机上运行多个虚拟机,每个虚拟机都是独立的一个环境
优点:程序环境不会相互产生影响,提供了一定程度的安全性
缺点:增加了操作系统,浪费了部分资源
-
容器化部署:与虚拟化类似,但是共享了操作系统
优点:
可以保证每个容器拥有自己的文件系统、CPU、内存、进程空间等
运行应用程序所需要的资源都被容器包装,并和底层基础架构解耦
容器化的应用程序可以跨云服务商、跨Linux操作系统发行版进行部署
-
容器化部署方式给带来很多的便利,但是也会出现一些问题,比如说:
- 一个容器故障停机了,怎么样让另外一个容器立刻启动去替补停机的容器
- 当并发访问量变大的时候,怎么样做到横向扩展容器数量
这些容器管理的问题统称为容器编排问题,为了解决这些容器编排问题,就产生了一些容器编排的软件:
- Swarm:Docker自己的容器编排工具
- Mesos:Apache的一个资源统一管控的工具,需要和Marathon结合使用
- Kubernetes:Google开源的的容器编排工具
1.2 kubernetes简介
kubernetes,是一个全新的基于容器技术的分布式架构领先方案,是谷歌严格保密十几年的秘密武器----Borg系统的一个开源版本,于2014年9月发布第一个版本,2015年7月发布第一个正式版本。
kubernetes的本质是一组服务器集群,它可以在集群的每个节点上运行特定的程序,来对节点中的容器进行管理。目的是实现资源管理的自动化,主要提供了如下的主要功能:
- 自我修复:一旦某一个容器崩溃,能够在1秒中左右迅速启动新的容器
- 弹性伸缩:可以根据需要,自动对集群中正在运行的容器数量进行调整
- 服务发现:服务可以通过自动发现的形式找到它所依赖的服务
- 负载均衡:如果一个服务起动了多个容器,能够自动实现请求的负载均衡
- 版本回退:如果发现新发布的程序版本有问题,可以立即回退到原来的版本
- 存储编排:可以根据容器自身的需求自动创建存储卷
1.3 kubernetes组件
一个kubernetes集群主要是由控制节点(master)、工作节点(node)构成,每个节点上都会安装不同的组件。
master:集群的控制平面,负责集群的决策 ( 管理 )
ApiServer : 资源操作的唯一入口,接收用户输入的命令,提供认证、授权、API注册和发现等机制
Scheduler : 负责集群资源调度,按照预定的调度策略将Pod调度到相应的node节点上
ControllerManager : 负责维护集群的状态,比如程序部署安排、故障检测、自动扩展、滚动更新等
Etcd :负责存储集群中各种资源对象的信息
node:集群的数据平面,负责为容器提供运行环境 ( 干活 )
Kubelet : 负责维护容器的生命周期,即通过控制docker,来创建、更新、销毁容器
KubeProxy : 负责提供集群内部的服务发现和负载均衡
Docker : 负责节点上容器的各种操作
下面,以部署一个nginx服务来说明kubernetes系统各个组件调用关系:
-
首先要明确,一旦kubernetes环境启动之后,master和node都会将自身的信息存储到etcd数据库中
-
一个nginx服务的安装请求会首先被发送到master节点的apiServer组件
-
apiServer组件会调用scheduler组件来决定到底应该把这个服务安装到哪个node节点上
在此时,它会从etcd中读取各个node节点的信息,然后按照一定的算法进行选择,并将结果告知apiServer
-
apiServer调用controller-manager去调度Node节点安装nginx服务
-
kubelet接收到指令后,会通知docker,然后由docker来启动一个nginx的pod
pod是kubernetes的最小操作单元,容器必须跑在pod中至此,
-
一个nginx服务就运行了,如果需要访问nginx,就需要通过kube-proxy来对pod产生访问的代理
这样,外界用户就可以访问集群中的nginx服务了
1.4 kubernetes概念
Master:集群控制节点,每个集群需要至少一个master节点负责集群的管控
Node:工作负载节点,由master分配容器到这些node工作节点上,然后node节点上的docker负责容器的运行
Pod:kubernetes的最小控制单元,容器都是运行在pod中的,一个pod中可以有1个或者多个容器
Controller:控制器,通过它来实现对pod的管理,比如启动pod、停止pod、伸缩pod的数量等等
Service:pod对外服务的统一入口,下面可以维护者同一类的多个pod
Label:标签,用于对pod进行分类,同一类pod会拥有相同的标签
NameSpace:命名空间,用来隔离pod的运行环境
名称 ip k8s-master 192.168.6.156 k8s-node1 192.168.6.152 k8s-node2 192.168.6.153 准备工作
-
# 关闭三台主机的防火墙和selinux、配置源还有swap分区空间 [root@k8s-master ~]# systemctl status firewalld ● firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled) Active: inactive (dead) Docs: man:firewalld(1) [root@k8s-master ~]# getenforce Disabled [root@k8s-master ~]# vi /etc/fstab //注释或者取消 #/dev/mapper/cs-swap none swap defaults 0 0 [root@k8s-node1 ~]# systemctl disable --now firewalld Removed /etc/systemd/system/multi-user.target.wants/firewalld.service. Removed /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service. [root@k8s-node1 ~]# setenforce 0 [root@k8s-node1 ~]# vi /etc/selinux/config SELINUX=disabled [root@k8s-node1 ~]# vi /etc/fstab #/dev/mapper/cs-swap none swap defaults 0 0 [root@k8s-node2 ~]# systemctl disable --now firewalld Removed /etc/systemd/system/multi-user.target.wants/firewalld.service. Removed /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service. [root@k8s-node2 ~]# setenforce 0 [root@k8s-node2 ~]# vi /etc/selinux/config SELINUX=disabled [root@k8s-node2 ~]# vi /etc/fstab #/dev/mapper/cs-swap none swap defaults 0 0
# 添加kubernetes阿里云YUM软件源,3台主机同样的配置 [root@master ~]# cat /etc/yum.repos.d/kubernetes.repo [kubernetes] name=Kubernetes baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64 enabled=1 gpgcheck=0 repo_gpgcheck=0 gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
# 安装kubeadm,kubelet和kubectl [root@k8s-master ~]# yum install -y kubelet-1.25.0 kubeadm-1.25.0 kubectl-1.25.0 [root@k8s-master ~]# systemctl enable kubelet # 只设置开机自启不启动
部署Kubernetes Master
# 生成默认配置文件 由于默认拉取镜像地址k8s.gcr.io国内无法访问,这里指定阿里云镜像仓库地址。 [root@k8s-master ~]# containerd config default > /etc/containerd/config.toml # 把配置文件里面的k8s.gcr.io替换成registry.aliyuncs.com/google_containers /重启 [root@k8s-master ~]# systemctl restart containerd [root@k8s-master ~]# kubeadm init \ # 初始化 > --apiserver-advertise-address=192.168.6.156 \ master主机的ip > --image-repository registry.aliyuncs.com/google_containers \ # # 使用阿里云的谷歌镜像仓库,应为国内登录不了谷歌官网 > --kubernetes-version v1.25.0 \ # kubernetes版本号 > --service-cidr=10.96.0.0/12 \ # service的网段 > --pod-network-cidr=10.244.0.0/16 #pod的网段 [init] Using Kubernetes version: v1.25.0 [preflight] Running pre-flight checks [WARNING FileExisting-tc]: tc not found in system path [preflight] Pulling images required for setting up a Kubernetes cluster [preflight] This might take a minute or two, depending on the speed of your internet connection [preflight] You can also perform this action in beforehand using 'kubeadm config images pull' [certs] Using certificateDir folder "/etc/kubernetes/pki" [certs] Generating "ca" certificate and key [certs] Generating "apiserver" certificate and key [certs] apiserver serving cert is signed for DNS names [k8s-master kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local] and IPs [10.96.0.1 192.168.6.156] [certs] Generating "apiserver-kubelet-client" certificate and key [certs] Generating "front-proxy-ca" certificate and key [certs] Generating "front-proxy-client" certificate and key [certs] Generating "etcd/ca" certificate and key [certs] Generating "etcd/server" certificate and key [certs] etcd/server serving cert is signed for DNS names [k8s-master localhost] and IPs [192.168.6.156 127.0.0.1 ::1] [certs] Generating "etcd/peer" certificate and key [certs] etcd/peer serving cert is signed for DNS names [k8s-master localhost] and IPs [192.168.6.156 127.0.0.1 ::1] [certs] Generating "etcd/healthcheck-client" certificate and key [certs] Generating "apiserver-etcd-client" certificate and key [certs] Generating "sa" key and public key [kubeconfig] Using kubeconfig folder "/etc/kubernetes" [kubeconfig] Writing "admin.conf" kubeconfig file [kubeconfig] Writing "kubelet.conf" kubeconfig file [kubeconfig] Writing "controller-manager.conf" kubeconfig file [kubeconfig] Writing "scheduler.conf" kubeconfig file [kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env" [kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml" [kubelet-start] Starting the kubelet [control-plane] Using manifest folder "/etc/kubernetes/manifests" [control-plane] Creating static Pod manifest for "kube-apiserver" [control-plane] Creating static Pod manifest for "kube-controller-manager" [control-plane] Creating static Pod manifest for "kube-scheduler" [etcd] Creating static Pod manifest for local etcd in "/etc/kubernetes/manifests" [wait-control-plane] Waiting for the kubelet to boot up the control plane as static Pods from directory "/etc/kubernetes/manifests". This can take up to 4m0s [apiclient] All control plane components are healthy after 7.502467 seconds [upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace [kubelet] Creating a ConfigMap "kubelet-config" in namespace kube-system with the configuration for the kubelets in the cluster [upload-certs] Skipping phase. Please see --upload-certs [mark-control-plane] Marking the node k8s-master as control-plane by adding the labels: [node-role.kubernetes.io/control-plane node.kubernetes.io/exclude-from-external-load-balancers] [mark-control-plane] Marking the node k8s-master as control-plane by adding the taints [node-role.kubernetes.io/control-plane:NoSchedule] [bootstrap-token] Using token: sy9jt7.9m9pgr1q6wsp60r4 [bootstrap-token] Configuring bootstrap tokens, cluster-info ConfigMap, RBAC Roles [bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to get nodes [bootstrap-token] Configured RBAC rules to allow Node Bootstrap tokens to post CSRs in order for nodes to get long term certificate credentials [bootstrap-token] Configured RBAC rules to allow the csrapprover controller automatically approve CSRs from a Node Bootstrap Token [bootstrap-token] Configured RBAC rules to allow certificate rotation for all node client certificates in the cluster [bootstrap-token] Creating the "cluster-info" ConfigMap in the "kube-public" namespace [kubelet-finalize] Updating "/etc/kubernetes/kubelet.conf" to point to a rotatable kubelet client certificate and key [addons] Applied essential addon: CoreDNS [addons] Applied essential addon: kube-proxy Your Kubernetes control-plane has initialized successfully! To start using your cluster, you need to run the following as a regular user: # 如果你想启用使用集群的话就要用下面的命令;如果是普通用户就执行下面的操作 mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config Alternatively, if you are the root user, you can run: # 如果你是管理员用户就执行下面的操作,但是我们一般不会这样操作。 因为这是临时的,我们需要做成永久生效的。下面会有做法 export KUBECONFIG=/etc/kubernetes/admin.conf # 设置一个环境变量告诉系统使用的哪个配置文件 You should now deploy a pod network to the cluster. # 你需要设置一个pod网络到集群中,使用下面的命令 Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at: https://kubernetes.io/docs/concepts/cluster-administration/addons/ Then you can join any number of worker nodes by running the following on each as root: #下面的命令是用来在被控主机上执行的,在被控主机执行过会 这台主机就会被加入到集群中 所以一定要记住这个命令或者把这个命令保存到文件中或其他记得的地方 kubeadm join 192.168.6.156:6443 --token sy9jt7.9m9pgr1q6wsp60r4 \ --discovery-token-ca-cert-hash sha256:495e642b59a5133ac67e0cf435e50e7ee66fead8e6f0e47b67e765eec2fd63cf [root@k8s-master ~]# echo 'export KUBECONFIG=/etc/kubernetes/admin.conf' > /etc/profile.d/k8s.sh [root@k8s-master ~]# source /etc/profile.d/k8s.sh [root@k8s-master ~]# echo $KUBECONFIG /etc/kubernetes/admin.conf
[root@k8s-master ~]# cd /etc/containerd/ [root@k8s-master containerd]# ls config.toml [root@k8s-master containerd]# scp config.toml k8s-node1:/etc/containerd/ config.toml 100% 6949 5.5MB/s 00:00 [root@k8s-master containerd]# scp config.toml k8s-node2:/etc/containerd/ config.toml 100% 6949 5.6MB/s 00:00 [root@k8s-master containerd]# systemctl restart containerd [root@k8s-node1 ~]# systemctl restart containerd [root@k8s-node2 ~]# systemctl restart containerd
安装Pod网络插件(CNI)
-
#master主机操作其他主机不用做。这一步前要确保主机可以正常访问quay.io这个registery(仓库),因为是从红帽官方quay.io拉取镜像 #kube-flannel.yml内容地址https://github.com/flannel-io/flannel/blob/master/Documentation/kube-flannel.yml [root@k8s-master ~]# vi kube-flannel.yml --- kind: Namespace apiVersion: v1 metadata: name: kube-flannel labels: pod-security.kubernetes.io/enforce: privileged --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: flannel rules: - apiGroups: - "" resources: - pods verbs: - get - apiGroups: - "" resources: - nodes verbs: - list - watch - apiGroups: - "" resources: - nodes/status verbs: - patch --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: 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: name: flannel namespace: kube-flannel --- kind: ConfigMap apiVersion: v1 metadata: name: kube-flannel-cfg namespace: kube-flannel labels: tier: node 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 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: flannelcni/flannel-cni-plugin:v1.1.0 for ppc64le and mips64le (dockerhub limitations may apply) image: docker.io/rancher/mirrored-flannelcni-flannel-cni-plugin:v1.1.0 command: - cp args: - -f - /flannel - /opt/cni/bin/flannel volumeMounts: - name: cni-plugin mountPath: /opt/cni/bin - name: install-cni #image: flannelcni/flannel:v0.19.2 for ppc64le and mips64le (dockerhub limitations may apply) image: docker.io/rancher/mirrored-flannelcni-flannel:v0.19.2 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: flannelcni/flannel:v0.19.2 for ppc64le and mips64le (dockerhub limitations may apply) image: docker.io/rancher/mirrored-flannelcni-flannel:v0.19.2 command: - /opt/bin/flanneld args: - --ip-masq - --kube-subnet-mgr resources: requests: cpu: "100m" memory: "50Mi" limits: 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 [root@k8s-master ~]# 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
加入Kubernetes Node
在初始化集群的时候会反馈很多的信息,其中最后一句话是最重要的,这句话是一个命令,是在node端执行的,表示将node主机添加到k8s集群中
-
# node1和node2节点执行 [root@k8s-node1 ~]# kubeadm join 192.168.6.156:6443 --token sy9jt7.9m9pgr1q6wsp60r4 \ > --discovery-token-ca-cert-hash sha256:495e642b59a5133ac67e0cf435e50e7ee66fead8e6f0e47b67e765eec2fd63cf [preflight] Running pre-flight checks [WARNING FileExisting-tc]: tc not found in system path [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. [root@k8s-node2 ~]# kubeadm join 192.168.6.156:6443 --token sy9jt7.9m9pgr1q6wsp60r4 \ > --discovery-token-ca-cert-hash sha256:495e642b59a5133ac67e0cf435e50e7ee66fead8e6f0e47b67e765eec2fd63cf [preflight] Running pre-flight checks [WARNING FileExisting-tc]: tc not found in system path [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. # 然后去master上查看受控节点的状态 [root@k8s-master ~]# kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-master Ready control-plane 27m v1.25.0 k8s-node1 Ready <none> 101s v1.25.0 k8s-node2 Ready <none> 89s v1.25.0 [root@k8s-master ~]# kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-master Ready control-plane 27m v1.25.0 k8s-node1 Ready <none> 2m28s v1.25.0 k8s-node2 Ready <none> 2m16s v1.25.0
# 管理容器,master上操作 [root@k8s-master ~]# kubectl get ns # 查看所有的名称空间类型 NAME STATUS AGE default Active 29m kube-flannel Active 7m kube-node-lease Active 29m kube-public Active 29m kube-system Active 29m # 自动运行的容器都是属于这一类 # 查看现有的容器状态 查看容器的状态的时候要指定名称空间 pods:所有的容器; -n:指定名称空间 [root@k8s-master ~]# kubectl get pods -n kube-system NAME READY STATUS RESTARTS AGE coredns-c676cc86f-rvpf4 1/1 Running 0 30m coredns-c676cc86f-t87c9 1/1 Running 0 30m etcd-k8s-master 1/1 Running 0 30m kube-apiserver-k8s-master 1/1 Running 0 30m kube-controller-manager-k8s-master 1/1 Running 0 30m kube-proxy-gljb7 1/1 Running 0 4m57s kube-proxy-lpxjl 1/1 Running 0 5m9s kube-proxy-tfxxj 1/1 Running 0 30m kube-scheduler-k8s-master 1/1 Running 0 30m #查看容器时在那个主机上运行、IP是多少 [root@k8s-master ~]# kubectl get pods -n kube-system -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES coredns-c676cc86f-rvpf4 1/1 Running 0 30m 10.244.0.2 k8s-master <none> <none> coredns-c676cc86f-t87c9 1/1 Running 0 30m 10.244.0.3 k8s-master <none> <none> etcd-k8s-master 1/1 Running 0 31m 192.168.6.156 k8s-master <none> <none> kube-apiserver-k8s-master 1/1 Running 0 31m 192.168.6.156 k8s-master <none> <none> kube-controller-manager-k8s-master 1/1 Running 0 31m 192.168.6.156 k8s-master <none> <none> kube-proxy-gljb7 1/1 Running 0 5m40s 192.168.6.153 k8s-node2 <none> <none> kube-proxy-lpxjl 1/1 Running 0 5m52s 192.168.6.152 k8s-node1 <none> <none> kube-proxy-tfxxj 1/1 Running 0 30m 192.168.6.156 k8s-master <none> <none> kube-scheduler-k8s-master 1/1 Running 0 31m 192.168.6.156 k8s-master <none> <none>
测试kubernetes集群
在Kubernetes集群中创建一个pod,验证是否正常运行:
# 创建一个deployment类型的的容器 名字叫nginx 镜像使用nginx [root@k8s-master ~]# kubectl create deployment nginx --image=nginx deployment.apps/nginx created # 暴露deployment类型中的nginx 端口号为80 类型为节点端口 # 这里的暴露是service的端口号,而且他是有IP的。因为我们访问容器时访问的service的IP地址 [root@k8s-master ~]# kubectl expose deployment nginx --port=80 --type=NodePort service/nginx exposed [root@k8s-master ~]# kubectl get pod,svc NAME READY STATUS RESTARTS AGE pod/nginx-76d6c9b8c-srtc9 1/1 Running 0 85s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 37m service/nginx NodePort 10.110.57.212 <none> 80:30073/TCP 30s #访问测试 [root@k8s-master ~]# curl http://10.110.57.212 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> html { color-scheme: light dark; } body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)