Skip to main content

k8s实验一 启动单个 NginxPod 并映射端口

比起 docker 容器,k8s 部署容器复杂一点,但是 k8s 可以更灵活地配置。

本文的实验尝试创建一个 nginx(版本1.19.0) 应用,并映射容器的80端口,实现外网通过32080、内网通过2080端口访问应用。

如果是用 docker 实现

用 docker 就非常简单

docker run -p 32080:80 nginx:1.19.0

此时外网可以通过 32080 端口访问 nginx 应用(无防火墙)。

接下来部署 k8s,k8s 常用配置文件来操作,类似于 docker-compose,配置文件比指令操作可以更详细地描述资源。编写完配置文件后,执行 kubectl apply -f <文件> 即可交给k8s解析。

编写配置文件,部署 nginx Pod

pod.yaml
# Source: pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: examplepod
  labels:
    e1podlabel: e1podvalue
    app: exampleapp
spec:
      containers:
      - name: e1container
        image: nginx:1.19.0
        imagePullPolicy: IfNotPresent
pod.yaml 带注释
# Source: pod.yaml
# 配置文件用到的解析版本,v1即可。用`kubectl api-versions`可以查看所有的 apiVersion。
apiVersion: v1
# 创建的资源类型,创建 Pod 就写 Pod。
kind: Pod
# 元数据,用来标识的资源的属性。比如资源名称
metadata:
  # 资源的名称。
  name: examplepod
  # 资源的标签,标签可以自定义。
  labels:
    # 示例的自定义标签 e1podlabel。
    e1podlabel: e1podvalue
    # 示例的另一个自定义标签 app。
    app: exampleapp
# 描述 Pod 的组成。
spec:
  # 该 Pod 运行需要哪些容器
  containers:
      # 容器名称,重名也没问题
    - name: e1container
      # 容器用到的镜像,相当于 docker-compose 的镜像名
      image: nginx:1.19.0
      # 如何拉取这个镜像,IfNotPresent(找不到再拉取),Always(每次创建都拉取)
      imagePullPolicy: IfNotPresent

详细字段说明

  • apiVersion 配置文件用到的解析版本,v1即可。用kubectl api-versions可以查看所有的 apiVersion。

  • kind 创建的资源类型,创建 Pod 就写 Pod。

  • metadata 元数据,用来标识的资源的属性。比如资源名称

  • metadata.name 元数据中,资源的名称。

  • metadata.labels 元数据中,资源的标签,标签可以自定义。

  • metadata.labels.e1podlabel 元数据中,示例的自定义标签 e1podlabel。

  • metadata.labels.app 元数据中,示例的另一个自定义标签 app。

  • spec 资源描述,描述 Pod 的组成部分。

  • spec.containers 该 Pod 运行需要哪些容器。

  • spec.containers.name 容器名称,重名也没问题。

  • spec.containers.image 容器用到的镜像,相当于 docker-compose 的镜像名。

  • spec.containers.imagePullPolicy 如何拉取这个镜像,简要说下值,默认是 Always,每次创建Pod都重新拉取镜像,所以为了节省流量或私有需求,这里用IfNotPresent,找不到再拉取。

    • Never 不拉取,直接用本地,如果本地也没有镜像,则报错。
    • IfNotPresent 如果本地已有镜像,则不拉取。本地没有再拉取。
    • Always 总是拉取镜像再运行。

    关于imagePullPolicy的详细解释: 提前拉取镜像

配置文件写完后,apply 即可:

kubectl apply -f pod.yaml

编写配置文件,部署端口映射服务(Service)

k8s 服务是给容器提供网络服务的,正常情况下Pod跑在容器里,网络是分离的,对Pod部署了服务后,外部网络就可以访问Pod了。以 docker 为例,服务类似于端口映射(-p参数)。

svc.yaml
# Source: svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: examplesvc
spec:
  type: NodePort
  selector:
    app: exampleapp
  ports:
    - protocol: TCP
      port: 2080
      targetPort: 80
      nodePort: 32080
svc.yaml 带注释
# Source: svc.yaml
# 同上,解析配置文件需要的版本
apiVersion: v1
# 资源类型,服务资源为 Service
kind: Service
# 元数据
metadata:
  # 服务的名称
  name: examplesvc
# 服务的描述
spec:
  # 服务发布类型,常用 ClusterIP(集群内网访问) NodePort(外网也能访问) LoadBalancer(负载均衡)
  type: NodePort
  # 服务按标签查找Pod,标签匹配就给该 Pod 发布端口
  selector:
    # 带有标签 app: exampleapp 的 Pod 将被发布端口
    app: exampleapp
  # 发布哪些端口
  ports:
      # 发布一个 TCP 端口
    - protocol: TCP
      # 集群内网访问的端口
      port: 2080
      # Pod 中的端口
      targetPort: 80
      # 外部访问的端口
      nodePort: 32080

详细字段说明

  • apiVersion 同上,解析配置文件需要的版本。

  • kind 资源类型,服务资源为 Service。

  • metadata 元数据。

  • metadata.name 该服务的名称。

  • spec 该服务的描述。

  • spec.type 服务发布类型,常用以下几种类型,默认是ClusterIP

    • ClusterIP 发布到集群内网,就是只能在集群机器之间访问,如果k8s是单机,则等于只能在本机访问。
    • NodePort 不仅内网,外网也能访问。本实验开放外网访问。
    • LoadBalancer

    关于type的详细解释: 发布服务(服务类型)

  • spec.selector 标签选择器,很重要!服务是按标签查找Pod的。部署服务的时候,指定Pod的标签,服务就会查找每个Pod有没有这个标签,有的话,给这些Pod提供端口映射。上文的Pod已经配置了标签app: exampleapp,而该服务仅要求标签app: exampleapp,则该服务可以正确找到到上文的Pod,打开端口映射了。

  • spec.ports 想要配置的端口

  • spec.ports.protocol 端口协议,TCP或UDP。

  • spec.ports.port 集群内网访问用的端口,本实验用 2080。

  • spec.ports.targetPort 最终转发到Pod的哪个端口,Pod中的Nginx跑80端口,所以是80。

  • spec.ports.nodePort 外网访问用的端口,本实验用 32080。

配置完了,apply 即可:

kubectl apply -f svc.yaml

检查运行结果

至此本实验的部署工作已经完成,接下来是查看运行状态。

查看运行的 Pod

kubectl get pod

查看 Pod 详细信息

# 格式: kubectl describe pod <Pod名称>
kubectl describe pod examplepod

查看 Pod 日志

# 格式: kubectl logs <Pod名称>
kubectl logs examplepod
# 一直查看日志,直到 CTRL+C
kubectl logs -f examplepod

查看部署的服务

kubectl get service
kubectl get svc

查看服务详细信息

kubectl describe service
kubectl describe svc

尝试在集群访问

kubectl get svc 可以看到部署的服务,其中有ClusterIP,拿着这个IP,在集群的任何一台机器都可以访问到该服务映射的端口。

# 在集群的任何一台机器执行
curl <ClusterIP>:2080

尝试在外网访问

curl <外网IP>:32080

随时可以关闭端口映射服务

不同于docker,k8s部分资源都可以独立地关闭,只是依赖它的资源无法使用而已。

这也是撰写部署Pod和Service的配置文件时,写完了可以先运行的原因。

k8s 按照资源名称操作。

删掉本实验的端口映射服务

# 任意一种执行都可, service 和 svc 等同
kubectl delete service examplesvc
kubectl delete svc examplesvc

删掉后,集群和外网都无法访问了。

重新部署本实验的端口映射

kubectl apply -f svc.yaml

清理部署资源

实验结束,总共创建了2个资源: Pod、Service。这些资源都有名称,可以用名称删除它们。

kubectl delete pod examplepod
kubectl delete svc examplesvc