资源对象介绍

在Kubernetets中,一切皆资源,所有的事物都被抽象为了API资源

kubernetes系统的API Server基于http/https接收并响应客户端的操作请求,它提供了一种基于资源的RESTful风格的编程结构,将集群的各种组件都抽象成为标准的REST资源,如Node、Namespace和Pod等

查看Kubernetes上的所有API资源

  1. [root@k8s-master ~]# kubectl api-resources

Kubernetes资源介绍 - 图1

工作负载型资源

Pod是工作负载型资源中的基础资源,它负责运行容器,并为其解决环境性的依赖,但是Pod可能会因为资源超限或者节点故障等原因意外停止,这些非正常终止的Pod资源就需要被重建,而这类工作就将由工作负载型的控制器来完成,通常也被成为Pod控制器

常见的Pod控制器有下列几种:

  • ReplicaSet:用于确保每个Pod副本在任意时刻均能满足目标数量
  • Deployment:它用于为Pod和ReplicaSet提供声明式更新,是建构在ReplicaSet之上的更为高级的控制器,这种控制器并不直接管理Pod,而是通过管理ReplicaSet来间接管理Pod,也就是说Deployment管理ReplicaSet,ReplicaSet管理Pod

Kubernetes资源介绍 - 图2

  • StatefulSet:用于管理有状态的持久化应用,如database服务程序,其与Deployment的不同之处在于StatefulSet会为每一个Pod创建一个独有的持久性标识符,并会确保各Pod之间的顺序
  • DaemonSet:用于确保每个节点都运行了某Pod的一个副本;当有节点加入集群时, 也会为他们新增一个 Pod;当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet将会删除它创建的所有 Pod

    • DaemonSet 的一些典型用法:

      • 在每个节点上运行集群守护进程
      • 在每个节点上运行日志收集守护进程
      • 在每个节点上运行监控守护进程
  • Job:用于管理运行完成后即可终止的应用,例如批处理作业任务

Service资源

Pod资源可能会因为任何意外故障而被重建,于是它需要固定的可被发现的方式

另外、Pod资源仅在集群内可见,它的客户端也可能是集群内的其他Pod资源,若要开放给外部网络中的用户访问,则需要事先将其暴露到集群外部,并要为同一种工作负载的访问流量进行负载均衡。

举个例子,考虑一个图片处理后端,它运行了3个副本,这些副本是可互换的 —— 前端不需要关心它们调用了哪个后端副本,然而组成这一组后端程序的 Pod 实际上可能会发生变化, 前端客户端不应该也没必要知道,而且也不需要跟踪这一组后端的状态

Service就是Kubernetes中最核心的资源对象之一Service和Pod之间是通过Label串起来相同的Service的Pod的Label是一样的,同一个Service下的所有Pod通过kube-proxy实现负载均衡,而每个Service都会分配一个全局唯一的虚拟IP,也就是cluster ip

配置与存储资源

Docker容器分层联合挂载的方式决定了不宜在容器内部存储需要持久化的数据,于是它通过引入挂载外部存储卷的方式来解决此类问题,而Kubernetes则为此提供了Volume资源,它支持众多类型的存储设 备或存储系统

集群级资源

Kubernetes还存在一些集群级别的资源,用于定义集群自身配置信息的对象,他们仅仅应该由集群管理员进行操作,常见的集群级资源有下列几个:

  • Namespace:指定资源对象名称的作用范围,绝大多数对象都隶属于某一个名称空间,如果不指定则默认隶属于default空间,可以自己创建一个Namespace

    • 使用命令kubectl get ns查看目前集群中的名称空间

      1. [root@k8s-master ~]# kubectl get ns
      2. NAME STATUS AGE
      3. default Active 3d23h
      4. kube-node-lease Active 3d23h
      5. kube-public Active 3d23h
      6. kube-system Active 3d23h
  • Node:Kubernetes集群的工作节点,其标识符在当前集群中必须是唯一的

  • Role:名称空间级别的由规则组成的权限集合

  • ClusterRole、RoleBinding、ClusterRoleBinding……

元数据型资源

此类对象用于为集群内部的其他资源配置其行为或特性

常见类型有:HPA,PodTemplate,LimitRange….

API版本查询

  • 使用命令kubectl api-versions查看所有的API版本
  1. [root@k8s-master ~]# kubectl api-versions
  2. admissionregistration.k8s.io/v1
  3. apiextensions.k8s.io/v1
  4. apiregistration.k8s.io/v1
  5. apps/v1
  6. authentication.k8s.io/v1
  7. authorization.k8s.io/v1
  8. autoscaling/v1
  9. autoscaling/v2
  10. autoscaling/v2beta1
  11. autoscaling/v2beta2
  12. batch/v1
  13. batch/v1beta1
  14. certificates.k8s.io/v1
  15. coordination.k8s.io/v1
  16. discovery.k8s.io/v1
  17. discovery.k8s.io/v1beta1
  18. events.k8s.io/v1
  19. events.k8s.io/v1beta1
  20. flowcontrol.apiserver.k8s.io/v1beta1
  21. flowcontrol.apiserver.k8s.io/v1beta2
  22. networking.k8s.io/v1
  23. node.k8s.io/v1
  24. node.k8s.io/v1beta1
  25. policy/v1
  26. policy/v1beta1
  27. rbac.authorization.k8s.io/v1
  28. scheduling.k8s.io/v1
  29. storage.k8s.io/v1
  30. storage.k8s.io/v1beta1
  31. v1
  • 使用命令kubectl api-resources,结果中的APIVERSION标明了API版本

Kubernetes资源介绍 - 图3

  • 使用命令kubectl explain 资源类型,在返回的结果中VERSION一栏标明了API版本

Kubernetes资源介绍 - 图4

除了使用kubectl来查询,还可以通过HTTP的方式来获取

  • 于本地8080端口上启动一个API Service的代理网关
  1. [root@k8s-master ~]# kubectl proxy --port=8080
  2. Starting to serve on 127.0.0.1:8080
  • 使用curl访问API资源
  1. [root@k8s-master ~]# curl localhost:8080/api/v1/nodes

资源清单

资源清单介绍

在Kubernetes中,一般用yaml格式的文件来创建符合预期期望的Pod,这样的yaml配置文件一般将其称为资源清单

K8S中的API Server在创建资源时采用JSON格式的数据,我们可以通过使用yaml格式的配置文件来提供配置,然后K8S内部自动帮我们转换为JSON格式,然后再提交

资源清单格式

  1. apiVersion:group/apiversion # 如果没有给定group名称,那么默认为core
  2. kind: # 资源类别
  3. metadata: # 资源元数据
  4. name:
  5. namespace: # k8s自身的namespace
  6. lables:
  7. annotations: # 主要目的是方便用户阅读查找
  8. spec: # 期望的状态
  9. status: # 当前状态,本字段由k8s自身维护,无需定义

定义资源配置清单时,尽管apiVersion、kind和metadata有章可循,但spec字段对不同的资源来说是千差万别,因此用户需要参考文档来了解各种可用属性字段

  • 查询Pods的帮助文档:kubectl explain pod

  • 查询Pods的spec的帮助文档:kubectl explain pods.spec

  • 查询Pods的metadata的帮助文档: kubectl explain pods.metadata

  • 查询Pods的apiVersion的帮助文档:kubectl explain pods.apiVersion

  • 查询Pods的spec.containers的帮助文档:kubectl explain pod.spec.containers

资源管理

  • 命令式对象管理:直接使用命令去操作kubernetes资源
  • 命令式对象配置:通过命令配置和配置文件去操作kubernetes资源
  • 声明式对象配置:通过apply命令和配置文件去操作kubernetes资源 | 类型 | 操作对象 | 适用环境 | 优点 | 缺点 | | —- | —- | —- | —- | —- | | 命令式对象管理 | 对象 | 测试 | 简单 | 只能操作活动对象,无法审计、跟踪 | | 命令式对象配置 | 文件 | 开发 | 可以审计、跟踪 | 项目大时,配置文件多,操作麻烦 | | 声明式对象配置 | 目录 | 开发 | 支持目录操作 | 意外情况下难以调试 |

命令式对象管理

使用kubectl命令

kubectl是kubernetes集群的命令行工具,通过它能够对集群本身进行管理,并能够在集群上进行容器化应用的安装部署

语法格式:

  1. kubectl [command] [type] [name] [flags]
  2. # comand:指定要对资源执行的操作,例如create、get、delete
  3. # type:指定资源类型,比如deployment、pod、service
  4. # name:指定资源的名称,名称大小写敏感
  5. # flags:指定额外的可选参数
  1. # 查看所有pod
  2. kubectl get pod
  3. # 查看某个pod
  4. kubectl get pod pod_name
  5. # 查看某个pod,以yaml格式展示结果
  6. kubectl get pod pod_name -o yaml

kubernetes允许对资源进行多种操作,可以通过—help查看详细的操作命令

  1. kubectl --help

示例

  • 创建一个Namespace
  1. [root@k8s-master ~]# kubectl create namespace dev
  2. namespace/dev created
  3. [root@k8s-master ~]# kubectl get ns
  4. NAME STATUS AGE
  5. default Active 4d
  6. dev Active 10s
  7. kube-node-lease Active 4d
  8. kube-public Active 4d
  9. kube-system Active 4d
  • 在这个Namspace下面创建并运行一个Nginx的Pod
  1. [root@k8s-master ~]# kubectl run pod --image=nginx:latest -n dev
  2. pod/pod created
  3. [root@k8s-master ~]# kubectl get pod -n dev
  • 删除这个Pod
  1. [root@k8s-master ~]# kubectl delete po pod -n dev
  2. pod "pod" deleted
  3. [root@k8s-master ~]# kubectl get pod -n dev
  4. No resources found in dev namespace
  • 删除创建的Namespace
  1. [root@k8s-master ~]# kubectl delete ns dev
  2. namespace "dev" deleted

命令式对象配置

命令式对象配置就是使用命令与配置文件一起来操作kubernetes资源

示例

  • 创建一个nginxpod.yaml,内容如下
  1. [root@k8s-master ~]# vim nginxpod.yaml
  2. apiversion: v1
  3. kind: Namespace
  4. apiversion: v1
  5. kind: Namespace
  6. metadata:
  7. name: dev
  8. ---
  9. apiversion: v1
  10. kind: Pod
  11. metadata:
  12. name: nginxpod
  13. namespace: dev
  14. spec:
  15. containers:
  16. - name: nginx-containers
  17. images: nginx:latest
  • 执行kubectl create -f命令,创建资源(-f表示指定文件名)
  1. [root@k8s-master ~]# kubectl create -f nginxpod.yaml
  2. namespace/dev created
  3. pod/nginxpod created

此时发现创建了两个资源对象,分别是namespace和pod

  • 使用kubectl get -f命令,查看资源
  1. [root@k8s-master ~]# kubectl get -f nginxpod.yaml
  2. NAME STATUS AGE
  3. namespace/dev Active 45s
  4. NAME READY STATUS RESTARTS AGE
  5. pod/nginxpod 1/1 Running 0 45s
  6. [root@k8s-master ~]# kubectl get pods -n dev
  7. NAME READY STATUS RESTARTS AGE
  8. nginxpod 1/1 Running 0 60s
  9. [root@k8s-master ~]# kubectl get ns
  10. NAME STATUS AGE
  11. default Active 4d1h
  12. dev Active 76s
  13. kube-node-lease Active 4d1h
  14. kube-public Active 4d1h
  15. kube-system Active 4d1h
  • 执行kubectl delete -f命令,删除资源
  1. [root@k8s-master ~]# kubectl delete -f nginxpod.yaml
  2. namespace "dev" deleted
  3. pod "nginxpod" deleted

总结:命令式对象配置的方式操作资源,可以简单的认为:命令 + yaml配置文件(里面是命令需要的各种参数)

声明式对象配置

声明式对象配置只有一个命令kubectl apply,和命令式对象配置很像

示例

  • 创建一个nginxpod.yaml,内容如下
  1. [root@k8s-master ~]# vim nginxpod.yaml
  2. apiversion: v1
  3. kind: Namespace
  4. apiversion: v1
  5. kind: Namespace
  6. metadata:
  7. name: dev
  8. ---
  9. apiversion: v1
  10. kind: Pod
  11. metadata:
  12. name: nginxpod
  13. namespace: dev
  14. spec:
  15. containers:
  16. - name: nginx-containers
  17. images: nginx:latest
  • 执行kubectl apply -f命令,创建资源(-f表示指定文件名)

    • 当再执行一次的时候,会提示已经创建了
    • 如果是命令式对象配置再执行一次就会报错,声明式对象配置不会报错
  1. [root@k8s-master ~]# kubectl apply -f nginxpod.yaml
  2. namespace/dev created
  3. pod/nginxpod created
  4. [root@k8s-master ~]# kubectl apply -f nginxpod.yaml
  5. namespace/dev unchanged
  6. pod/nginxpod unchanged

总结:其实声明式对象配置就是使用apply命令描述一个资源最终的状态(在yaml中定义状态)

使用kubectl apply操作资源:

  • 如果资源不存在,就创建,相当于kubectl create

  • 如果资源已存在,就更新,相当于kubectl patch

使用推荐

创建资源、更新资源时,使用声明式对象配置kubectl apply -f xxx.yaml

删除资源时,使用声明式对象配置kubectl delete -f xxx.yaml

查询资源时,使用命令式对象管理kubectl get(describe) 资源名称

实战入门

Namespace

Namespace是kubernetes系统中的一种非常重要资源,它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离

默认情况下,kubernetes集群中的所有的Pod都是可以相互访问的,但是在实际中,可能不想让两个Pod之间进行互相的访问,那此时就可以将两个Pod划分到不同的namespace下,形成逻辑上的“组”,方便不同的组的资源进行隔离使用和管理

Kubernetes资源介绍 - 图5

Kubernetes在集群启动之后,会默认创建几个namespace

  1. [root@k8s-master ~]# kubectl get namespace
  2. NAME STATUS AGE
  3. default Active 10d
  4. kube-node-lease Active 10d
  5. kube-public Active 10d
  6. kube-system Active 10d

default:所有未指定Namespace的对象都会被分配在default命名空间

kube-node-lease:集群节点之间的心跳维护,v1.13开始引入

kube-public:此命名空间下的资源可以被所有人访问(包括未认证用户)

kube-system:所有由Kubernetes系统创建的资源都处于这个命名空间

具体操作

查看

  1. # 查看所有的namespace
  2. kubectl get namespace # 可以将namespace简写成ns
  3. # 查看指定的namespace
  4. kubectl get ns default
  5. # 指定输出格式:kubectl get ns 名称 -o 格式参数(wide/json/yaml)
  6. kubectl get ns default -o yaml
  7. # 查看指定的namespace详情
  8. kubectl describe ns default

创建

  1. kubectl create ns dev

删除

  1. kubectl delete ns dev

配置文件方式

  1. # ns-dev.yaml
  2. apiVersion: v1
  3. kind: Namespace
  4. metadata:
  5. name: dev
  6. # 创建:kubectl apply -f ns-dev.yaml
  7. # 删除:kubectl delete -f ns-dev.yaml
  8. # 查看:kubectl get -f ns-dev.yaml

Pod

Pod是kubernetes集群进行管理的最小单元,程序要运行必须部署在容器中,而容器必须存在于Pod中,Pod可以认为是容器的封装,一个Pod中可以存在一个或者多个容器

Kubernetes资源介绍 - 图6

kubernetes在集群启动之后,集群中的各个组件也都是以Pod方式运行的,可以通过下面命令查看:

  1. [root@k8s-master ~]# kubectl get pods -n kube-system
  2. NAME READY STATUS RESTARTS AGE
  3. coredns-6d8c4cb4d-4b229 1/1 Running 10 (6m30s ago) 11d
  4. coredns-6d8c4cb4d-tfbxr 1/1 Running 10 (6m30s ago) 11d
  5. etcd-k8s-master 1/1 Running 10 (6m30s ago) 11d
  6. kube-apiserver-k8s-master 1/1 Running 10 (6m30s ago) 11d
  7. kube-controller-manager-k8s-master 1/1 Running 10 (6m30s ago) 11d
  8. kube-flannel-ds-7qvjp 1/1 Running 10 (6m30s ago) 11d
  9. kube-flannel-ds-z5hzt 1/1 Running 12 (6m21s ago) 11d
  10. kube-proxy-4rpcz 1/1 Running 11 (6m21s ago) 11d
  11. kube-proxy-dkft4 1/1 Running 10 (6m30s ago) 11d
  12. kube-proxy-s4hvq 1/1 Running 10 (6m26s ago) 11d
  13. kube-scheduler-k8s-master 1/1 Running 10 (6m30s ago) 11d

具体操作

创建并运行

kubernetes一般不单独运行Pod的命令,都是通过Pod控制器来实现的

# 命令格式: kubectl create deploy (pod控制器名称) [参数]
# --image 指定Pod的镜像
# --port 指定端口
# --namespace 指定namespace
kubectl create deploy nginx --image=nginx --port=80 -n dev deployment.apps/nginx created

查看

# 查看dev下的所有pod信息
kubectl get pods -n [namespace名称]

# 查看某个pod的详细信息
kubectl describe pod [pod名称] -n [namespace名称]

# 查看pod的详细状态(IP、节点等)
kubectl get pods -n [namespace名称] -o wide

删除

# 删除指定pod
kubectl delete pod [pod名称] -n [namespace名称]
# 如果删掉了又被重新创建了,那么就是pod控制器在监控pod的状态,当pod死亡时,会立即创建一个新的pod,如果要删除pod,就需要把pod控制器删除

# 例如一个deploy控制器,名为nginx,创建了pod,那么删除就按下列步骤进行
kubectl get deploy -n dev        # 查看deploy资源类型的控制器的名称
kubectl delete deploy nginx -n dev        # 删除deploy控制器nginx

配置文件方式

# pod-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  namespace: dev
spec:
  containers:
  - image: nginx:latest
    name: pod
    ports:
    - name: nginx-port
      containerPort: 80
      protocol: TCP
# 创建:kubectl apply -f pod-nginx.yaml
# 删除:kubectl delete -f pod-nginx.yaml
# 查看:kubectl get -f pod-nginx.yaml

Label

Label是kubernetes系统中的一个重要概念,它的作用就是在资源上添加标识,用来对它们进行区分和选择

Label的特点:

  • 一个Label会以key/value键值对的形式附加到各种对象上,如Node、Pod、Service等等

  • 一个资源对象可以定义任意数量的Label ,同一个Label也可以被添加到任意数量的资源对象上去

  • Label通常在资源对象定义时确定,当然也可以在对象创建后动态添加或者删除

可以通过Label实现资源的多维度分组,以便灵活、方便地进行资源分配、调度、配置、部署等管理工作

一些常用的Label 示例如下:

  • 版本标签:"version":"release""version":"stable"……

  • 环境标签:"environment":"dev""environment":"test""environment":"pro"

  • 架构标签:"tier":"frontend""tier":"backend"

标签定义完毕之后,还要考虑到标签的选择,这就要使用到标签选择器(Label Selector),即:

Label用于给某个资源对象定义标识,而Label Selector用于查询和筛选拥有某些标签的资源对象

当前有两种Label Selector:

  1. 基于等式的Label Selector

    • name = slave:选择所有包含Label中key=”name”且value=”slave”的对象
    • env!= production:选择所有包括Label中的key=”env”且value不等于”production”的对象
  2. 基于集合的Label Selector

    • name in (master, slave):选择所有包含Label中的key=”name”且value=”master”或”slave”的对象
    • name not in (frontend): 选择所有包含Label中的key=”name”且value不等于”frontend”的对象

标签的选择条件可以使用多个,此时将多个Label Selector进行组合,使用逗号”,”进行分隔即可,例如:

name=slave,env!=production

name not in (frontend),env!=production

具体操作

打标签

# 打标签,语法格式:kubectl label pods [pod名称] key=value -n [namespace名称]
kubectl label pods pod-example version=1.0 -n dev

# 更新标签,语法格式:.... --overwrite
kubectl label pods pod-example version=2.0 -n dev --overwrite

查看标签

# 显示某个资源的所有标签
kubectl get pods pod-example --show-labels -n dev

# 指定显示某个资源特定的标签
kubectl get pods pod-example -L env,version -n dev

标签选择器

# 一个标签选择器,选择出env不等于qq的pod
kubectl get pods -l "env!=qq" --show-labels -n dev

# 一个标签选择器,选择出标签env等于qq或qa中的一个的所有pod
kubectl get pods -l "env in (qq,qa)" --show-labels -n dev

# 多个标签选择器,选择出env=qq并且version=2.0的pod
kubectl get pods -l "env=qq,version=2.0" --show-labels -n dev

删除标签

# 语法格式:kubectl label pods [pod名称] key- -n [namespace名称]
kubectl label pods pod-example version- -n dev

配置文件方式

# vim pod1.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-example
  labels:
    env: qa
    tier: frontend
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
      protocol: TCP

Deployment

在kubernetes中,Pod是最小的控制单元,但是kubernetes很少直接控制Pod,一般都是通过Pod控制器来完成控制Pod

Pod控制器用于Pod的管理,确保Pod资源符合预期的状态,当Pod的资源出现故障时,会尝试进行重启或重建Pod

在kubernetes中Pod控制器的种类有很多,这里只介绍一种:Deployment

Kubernetes资源介绍 - 图7

具体操作

查看

# 首先创建一个deployment类型的控制器nginx,其中的pod为3个,镜像为nginx
kubectl create deploy nginx --image=nginx:latest --port=80 --replicas=3 -n dev
# 查看deployment的信息
kubectl get deploy -n dev (-o wide)
'--------------------------------------'
NAME READY     UP-TO-DATE     AVAILABLE      AGE
nginx 3/3          3             3           2m42s
# UP-TO-DATE:成功升级的副本数量
# AVAILABLE:可用副本的数量

# 查看详细信息
kubectl describe deploy nginx -n dev

删除

kubectl delete deploy nginx -n dev

配置文件操作

# deploy-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      run: nginx
  template:
    metadata:
      labels:
        run: nginx
    spec:
      containers:
      - image: nginx:latest
        name: nginx
        ports:
        - containerPort: 80
          protocol: TCP
# 创建:kubectl create -f deploy-nginx.yaml
# 删除:kubectl delete -f deploy-nginx.yaml

Service

虽然每个Pod都会分配一个单独的Pod IP,然而却存在如下两问题:

  • Pod IP 会随着Pod的重建产生变化
  • Pod IP 仅仅是集群内可见的虚拟IP,外部无法访问

这样对于访问这个服务带来了难度,因此,Kubernetes设计了Service来解决这个问题

Service可以看作是一组同类Pod对外的访问接口,借助Service应用可以方便地实现服务发现和负载均衡

Kubernetes资源介绍 - 图8

具体操作

创建集群内部可访问的service

[root@k8s-master ~]# kubectl expose deploy nginx --name=svc-nginx --type=ClusterIP --port=80 --target-port=80 -n dev
service/svc-nginx exposed
[root@k8s-master ~]# kubectl get svc svc-nginx -n dev -o wide
NAME        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE   SELECTOR
svc-nginx   ClusterIP   172.16.93.114   <none>        80/TCP    10s   app=nginx
[root@k8s-master ~]# curl 172.16.93.114

创建集群外部也可访问的Service

[root@k8s-master ~]# kubectl expose deploy nginx --name=svc-nginx1 --type=NodePort --port=80 --target-port=80 -n dev
service/svc-nginx1 exposed
[root@k8s-master ~]# kubectl get svc svc-nginx1 -n dev -o wide
NAME         TYPE       CLUSTER-IP      EXTERNAL-IP PORT(S)        AGE   SELECTOR
svc-nginx1   NodePort   172.16.252.67   <none>        80:31640/TCP   5s    app=nginx

# 下面两种方式均可访问到
[root@k8s-master ~]# curl 172.16.252.67
[root@k8s-master ~]# curl 192.168.31.100:31640

删除

kubectl delete svc svc-nginx1 -n dev

配置文件方式

# svc-nginx.yaml
apiVersion: v1
kind: Service
metadata:
  name: svc-nginx
  namespace: dev
spec:
  clusterIP: 172.16.99.99 #固定svc的内网ip
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: nginx
  type: ClusterIP

[root@k8s-master ~]# kubectl apply -f svc-nginx.yaml 
[root@k8s-master ~]# kubectl get svc -n dev
NAME        TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
svc-nginx   ClusterIP   172.16.99.99   <none>        80/TCP    3s
[root@k8s-master ~]# curl 172.16.99.99