在本文中,咱们从技术细节上对kubernetes进行简单运用介绍,利用一些yaml脚本层面上实例告诉你们kubernetes基本概念。Kubernetes以及它呈现出的编程范式值得你去使用和整合到本身的技术栈中。php
你们若有兴趣,能够关注由达观数据出品的更多经典好文datagrand达观数据html
Kubernetes最初认为是谷歌开源的容器集群管理系统,是Google多年大规模容器管理技术Borg或Omega的开源版本。准确来讲的话,kubernetes更是一个全新的平台,一个全新的
平台管理工具,它是专门为job和service设计。彻底开放,2014年6月开始接受公开的commit,任何人均可以提供意见。因为kubernetes简化了开发、运维和管理负荷,愈来愈多
的企业开始在生产环境使用,所以kubernetes获得了迅速的发展。node
Kubernetes主要由如下几个核心组件组成:mysql
若是只是为了了解kubernetes,可使用minikube的方式进行单机安装,minikube 实际就是本地建立了一个虚拟机,里面运行了kubernetes 的一些必要的环境,至关于 k8s 的服务环境,建立 pod,service,deployment等都是在里面进行建立和管理。
在本文中,我使用kubeadm方式安装kubernetes 1.10.0,具体kubernetes部署步骤:nginx
请注意:上述环境只是测试环境,生产环境部署大同小异。git
Container(容器)是一种便携式、轻量级的操做系统级虚拟化技术。它使用 namespace 隔离不一样的软件运行环境,并经过镜像自包含软件的运行环境,
从而使得容器能够很方便的在任何地方运行。因为容器体积小且启动快,所以能够在每一个容器镜像中打包一个应用程序。这种一对一的应用镜像关系拥有不少好处。使用容器,
不须要与外部的基础架构环境绑定, 由于每个应用程序都不须要外部依赖,更不须要与外部的基础架构环境依赖。完美解决了从开发到生产环境的一致性问题。
容器一样比虚拟机更加透明,这有助于监测和管理。尤为是容器进程的生命周期由基础设施管理,而不是由容器内的进程对外隐藏时更是如此。最后,
每一个应用程序用容器封装,管理容器部署就等同于管理应用程序部署。
在 Kubernetes 必需要使用 Pod 来管理容器,每一个 Pod 能够包含一个或多个容器。web
上面已经说了“Pod是kubernetes中你能够建立和部署的最小也是最简的单位。一个Pod表明着集群中运行的一个进程。”Pod中封装着应用的容器(有的状况下是好几个容器),
存储、独立的网络IP,管理容器如何运行的策略选项。Pod表明着部署的一个单位:kubernetes中应用的一个实例,可能由一个或者多个容器组合在一块儿共享资源。
请注意:Docker是kubernetes中最经常使用的容器运行时,可是Pod也支持其余容器运行时。redis
(1)一个Pod中运行一个容器
“每一个Pod中一个容器”的模式是最多见的用法;在这种使用方式中,你能够把Pod想象成是单个容器的封装,kuberentes管理的是Pod而不是直接管理容器。sql
apiVersion: v1 kind: Pod metadata: name: nginx-test labels: app: web spec: containers: - name: front-end image: nginx:1.7.9 ports: - containerPort: 80
建立Pod: kubectl create -f ./pod1-deployment\ 查看Pod: kubectl get po 查看Pod详细状况: kubectl describe po nginx-test 进入到Pod(容器)内部: kubectl exec -it nginx-test /bin/bash
(2)在一个Pod中同时运行多个容器
说明:在一个Pod中同时运行多个容器是一种比较高级的用法。只有当你的容器须要紧密配合协做的时候才考虑用这种模式。
一个Pod中也能够同时封装几个须要紧密耦合互相协做的容器,它们之间共享资源。这些在同一个Pod中的容器能够互相协做成为一个service单位——一个容器共享文件,
另外一个“sidecar”容器来更新这些文件。Pod将这些容器的存储资源做为一个实体来管理。docker
apiVersion: v1 kind: Pod metadata: name: rss-site labels: app: web spec: containers: - name: front-end image: nginx:1.7.9 ports: - containerPort: 80 - name: rss-reader image: redis ports: - containerPort: 88
建立Pod: kubectl create -f ./test-deployment 查看pod kubectl get po 查看Pod详细状况 kubectl describe po rss-site 进入front-end内部: kubectl exec -it rss-site -c front-end /bin/bash 进入rss-reade内部: kubectl exec -it rss-site -c rss-reader /bin/bash
以上是关于Pod的简单介绍,如需了解更多,请参考Pod
Node 是 Pod 真正运行的主机,能够物理机,也能够是虚拟机。为了管理 Pod,每一个 Node 节点上至少要运行 container runtime(好比 docker 或者 rkt)、kubelet 和 kube-proxy 服务。
Namespace 是对一组资源和对象的抽象集合,好比能够用来将系统内部的对象划分为不一样的项目组或用户组。常见的 pods, services, replication controllers 和 deployments 等都是属于
某一个 namespace 的(默认是 default),而 node, persistentVolumes 等则不属于任何 namespace。
咱们既然有Pod了,为何还要使用Deployment呢?这是由于实际工做中,咱们不多会直接在kubernetes中建立单个Pod。由于Pod的生命周期是短暂的,用后即焚的实体。
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义(declarative)方法,用来替代之前的ReplicationController 来方便的管理应用。
你只须要在 Deployment 中描述想要的目标状态是什么,Deployment controller 就会帮你将 Pod 和ReplicaSet 的实际状态改变到你的目标状态。你能够定义一个全新的 Deployment 来建立
ReplicaSet 或者删除已有的 Deployment 并建立一个新的来替换。
RC是K8s集群中最先的保证Pod高可用的API对象。经过监控运行中的Pod来保证集群中运行指定数目的Pod副本。指定的数目能够是多个也能够是1个;少于指定数目,RC就会启动运行新的Pod副本;
多于指定数目,RC就会杀死多余的Pod副本。即便在指定数目为1的状况下,经过RC运行Pod也比直接运行Pod更明智,由于RC也能够发挥它高可用的能力,保证永远有1个Pod在运行。RC是K8s较早期
的技术概念,只适用于长期伺服型的业务类型,好比控制小机器人提供高可用的Web服务。
RS是新一代RC,提供一样的高可用能力,区别主要在于RS后来居上,能支持更多种类的匹配模式。副本集对象通常不单独使用,而是做为Deployment的理想状态参数使用。
好比,咱们这里定义一个简单的nginx应用:
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: nginx-test namespace: test spec: replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80
建立deploy kubectl create -f ./nginx-deployment 查看deploy kubectl get deploy --namespace=test 查看rs(副本集) kubectl get rs --namespace=test 查看pods(容器组) kubectl get po --namespace=test
关于Deployment的应用还有不少,如:扩容、缩容、滚动升级、回滚应用等,这里因为篇幅的问题再也不一一介绍,详见Deployment的应用
Label 是识别 Kubernetes 对象的标签,以 key/value 的方式附加到对象上(key 最长不能超过 63 字节,value 能够为空,也能够是不超过 253 字节的字符串)。
Label 不提供惟一性,而且实际上常常是不少对象(如 Pods)都使用相同的 label 来标志具体的应用。
Label 定义好后其余对象可使用 Label Selector 来选择一组相同 label 的对象(好比 ReplicaSet 和 Service 用 label 来选择一组 Pod)。Label Selector 支持如下几种方式:
Service account是为了方便Pod里面的进程调用Kubernetes API或其余外部服务。
运行在pod里的进程须要调用Kubernetes API以及非Kubernetes API的其它服务。Service Account它并非给kubernetes集群的用户使用的,而是给pod里面的进程使用的,它为pod提供必要的身份认证。
apiVersion: v1 kind: Namespace metadata: name: datagrand labels: name: test
建立namespace:test kubectl create -f ./test.yaml 查看命名空间test的sa kubectl get sa -n test 查看命名空间test生成的default kubectl get sa default -o yaml -n test 咱们能够建立Deployment时,使用这个test命名空间了,如上例Deployment实战。
Service Account为服务提供了一种方便的认知机制,但它不关心受权的问题。能够配合RBAC来为Service Account鉴权:
咱们在Kubernetes Dashboard1.8.3部署中,碰到首次登入出现访问权限报错的问题,缘由就是ServiceAccount的建立问题。
apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: kubernetes-dashboard labels: k8s-app: kubernetes-dashboard roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: kubernetes-dashboard namespace: kube-system
Service Account介绍请参考博文
Secret解决了密码、token、密钥等敏感数据的配置问题,而不须要把这些敏感数据暴露到镜像或者Pod Spec中。Secret能够以Volume或者环境变量的方式使用。
Opaque类型的数据是一个map类型,要求value是base64编码格式: 建立admin帐户 echo -n "admin" | base64 YWRtaW4= echo -n "1f2d1e2e67df" | base64 MWYyZDFlMmU2N2Rm
建立secret.yaml cat >> secrets.yml << EOF apiVersion: v1 kind: Secret metadata: name: mysecret type: Opaque data: password: MWYyZDFlMmU2N2Rm username: YWRtaW4=
建立secret kubectl create -f secrets.yml
查看secret运行状态 kubectl get secret --all-namespaces
apiVersion: v1 kind: Pod metadata: name: mypod labels: name: wtf spec: volumes: - name: secrets secret: secretName: mysecret containers: - image: nginx:1.7.9 name: nginx volumeMounts: - name: secrets mountPath: "/etc/secrets" readOnly: true ports: - name: cp containerPort: 5432 hostPort: 5432
说明:这样就能够经过文件的方式挂载到容器内,在/etc/secrets目录下回
生成这个文件。
apiVersion: extensions/v1beta1 kind: Deployment metadata: name: wordpress-deployment spec: replicas: 2 template: metadata: labels: app: wordpress spec: containers: - name: "wordpress" image: "wordpress:latest" ports: - containerPort: 80 env: - name: WORDPRESS_DB_USER valueFrom: secretKeyRef: name: mysecret key: username - name: WORDPRESS_DB_PASSWORD valueFrom: secretKeyRef: name: mysecret key: password
查看Pod运行状态 kubectl get po NAME READY STATUS RESTARTS AGE wordpress-deployment-6b569fbb7d-8qcpg 1/1 Running 0 2m wordpress-deployment-6b569fbb7d-xwwkg 1/1 Running 0 2m
进入容器内部查看环境变量 kubectl exec -it wordpress-deployment-694f4c79b4-cpsxw /bin/bash root@wordpress-deployment-694f4c79b4-cpsxw:/var/www/html# env WORDPRESS_DB_USER=admin WORDPRESS_DB_PASSWORD=1f2d1e2e67df
想要了解更多,请详见Kubernetes的Secret
ConfigMaps容许你将配置文件、命令行参数或环境变量中读取的配置信息与docker image分离,以保持集装箱化应用程序的便携性。即ConfigMap API给咱们提供了向容器中注入配置信息的机制。
ConfigMap API资源用来保存key-value pair配置数据,这个数据能够在pods里使用,或者被用来为像controller同样的系统组件存储配置数据。虽然ConfigMap跟Secrets相似,可是ConfigMap更方便的处理不含敏感信息的字符串。
注意:ConfigMaps不是属性配置文件的替代品。ConfigMaps只是做为多个properties文件的引用。你能够把它理解为Linux系统中的/etc目录,专门用来存储配置文件的目录。
kind: ConfigMap apiVersion: v1 metadata: creationTimestamp: 2016-02-18×××9:14:38Z name: example-config namespace: default data: example.property.1: hello example.property.2: world example.property.file: |- property.1=value-1 property.2=value-2 property.3=value-3
data一栏包括了配置数据,ConfigMap能够被用来保存单个属性,也能够用来保存一个配置文件。 配置数据能够经过不少种方式在Pods里被使用。ConfigMaps能够被用来:
更多ConfigMap实战,详见ConfigMap - Kubernetes
容器磁盘上文件的生命周期是短暂的,这就使得在容器中运行重要应用时出现一些问题。好比,当容器崩溃时,kubelet会重启它,可是容器中的文件将丢失--容器以干净的状态
(镜像最初的状态)从新启动。其次,在 Pod 中同时运行多个容器时,这些容器之间一般须要共享文件。Kubernetes 中的 Volume 抽象就很好的解决了这些问题。
Docker 中也有一个 volume 的概念,尽管它稍微宽松一些,管理也不多。在 Docker 中,卷就像是磁盘或是另外一个容器中的一个目录。它的生命周期不受管理,直到最近才有了 local-disk-backed 卷。Docker 如今提供了卷驱动程序,可是功能还很是有限(例如Docker1.7只容许每一个容器使用一个卷驱动,而且没法给卷传递参数)。
Kubernetes 中的卷有明确的寿命——与封装它的 Pod 相同。因此,卷的生命比 Pod 中的全部容器都长,当这个容器重启时数据仍然得以保存。固然,当 Pod 再也不存在时,卷也将不复存在。也许更重要的是,Kubernetes 支持多种类型的卷,Pod 能够同时使用任意数量的卷。
要使用卷,须要为 pod 指定为卷(spec.volumes 字段)以及将它挂载到容器的位置(spec.containers.volumeMounts 字段)。
Kubernetes 支持如下类型的卷:
awsElasticBlockStore、azureDisk、azureFile、cephfs、csi、downwardAPI、emptyDir、fc (fibre channel)、flocker、gcePersistentDisk、gitRepo、glusterfs、hostPath、iscsi、local、nfs、persistentVolumeClaim、projected、portworxVolume、quobyte、rbd、scaleIO、secret、storageos、vsphereVolume等
K8S的存储系统从基础到高级大体分为三个层次:普通Volume,Persistent Volume 和动态存储供应。
最简单的普通Volume是单节点Volume。它和Docker的存储卷相似,使用的是Pod所在K8S节点的本地目录。
它和普通Volume的区别是什么呢?
普通Volume和使用它的Pod之间是一种静态绑定关系,在定义Pod的文件里,同时定义了它使用的Volume。Volume 是Pod的附属品,咱们没法单首创建一个Volume,由于它不是一个独立的K8S资源对象。
而Persistent Volume 简称PV是一个K8S资源对象,因此咱们能够单首创建一个PV。它不和Pod直接发生关系,而是经过Persistent Volume Claim,简称PVC来实现动态绑定。Pod定义里指定的是PVC,而后PVC会根据Pod的要求去自动绑定合适的PV给Pod使用。
PV的访问模式有三种:
通常来讲,PV和PVC的生命周期分为5个阶段:
根据这5个阶段,Volume的状态有如下4种:
变成Released的PV会根据定义的回收策略作相应的回收工做。有三种回收策略:
在实际使用场景里,PV的建立和使用一般不是同一我的。这里有一个典型的应用场景:管理员建立一个PV池,开发人员建立Pod和PVC,PVC里定义了Pod所需存储的大小和访问模式,而后PVC会到PV池里自动匹配最合适的PV给Pod使用。
前面在介绍PV的生命周期时,提到PV的供给有两种方式,静态和动态。其中动态方式是经过StorageClass来完成的,这是一种新的存储供应方式。
使用StorageClass有什么好处呢?除了由存储系统动态建立,节省了管理员的时间,还有一个好处是能够封装不一样类型的存储供PVC选用。在StorageClass出现之前,PVC绑定一个PV只能根据两个条件,一个是存储的大小,另外一个是访问模式。在StorageClass出现后,等于增长了一个绑定维度。
好比这里就有两个StorageClass,它们都是用谷歌的存储系统,可是一个使用的是普通磁盘,咱们把这个StorageClass命名为slow。另外一个使用的是SSD,咱们把它命名为fast。
在PVC里除了常规的大小、访问模式的要求外,还经过annotation指定了Storage Class的名字为fast,这样这个PVC就会绑定一个SSD,而不会绑定一个普通的磁盘。
限于篇幅问题,我这里简单说一下emptyDir、nfs、PV和PVC。
EmptyDir类型的volume建立于pod被调度到某个宿主机上的时候,而同一个pod内的容器都能读写EmptyDir中的同一个文件。一旦这个pod离开了这个宿主机,EmptyDir中的数据就会被永久删除。因此目前EmptyDir类型的volume主要用做临时空间,好比Web服务器写日志或者tmp文件须要的临时目录。
apiVersion: v1 kind: Pod metadata: labels: name: test-emptypath role: master name: test-emptypath spec: containers: - name: test-emptypath image: nginx:1.7.9 volumeMounts: - name: log-storage mountPath: /tmp/ volumes: - name: log-storage emptyDir: {}
apiVersion: v1 kind: Pod metadata: name: datagrand spec: containers: - name: test1 image: nginx:1.7.9 volumeMounts: - name: log-storage mountPath: /usr/share/nginx/html - name: test2 image: centos volumeMounts: - name: log-storage mountPath: /html command: ["/bin/sh","-c"] args: - while true;do data >> /html/index.html; sleep 1; done volumes: - name: log-storage emptyDir: {}
简单解释下上面的内容:
在这个例子中,咱们定义了一个名为HTML的卷。它的类型是emptyDir,这意味着当一个Pod被分配到一个节点时,卷先被建立,并只要Pod在节点上运行时,这个卷仍存在。正如名字所说,它最初是空的。第一容器运行nginx的
服务器并将共享卷挂载到目录/ usr /share/ nginx /html。第二容器使用centos的镜像,并将共享卷挂载到目录/HTML。每一秒,第二容器添加当前日期和时间到index.html文件中,它位于共享卷。当用户发出一个HTTP请求到Pod,
nginx的服务器读取该文件并将其传递给响应请求的用户。
更多volume实战,详见Kubernetes部分Volume类型介绍及yaml示例--emptyDir
nfs 卷容许将现有的 NFS(网络文件系统)共享挂载到你的容器中。不像 emptyDir,当删除 Pod 时,nfs 卷的内容被保留,卷仅仅是被卸载。这意味着 NFS 卷能够预填充数据,而且能够在 pod 之间“切换”数据。 NFS 能够被多个写入者同时挂载。
apiVersion: v1 kind: Pod metadata: name: nginx-test labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80 volumeMounts: #Mount the path to the container - mountPath: "/tmp/" name: pv0003 volumes: - name: pv0003 nfs: #fixed:This ip is the address of the nfs server server: 192.168.246.169 #fixed:This path is shared externally by the nfs server path: "/data"
更多volume实战,详见Kubernetes部分Volume类型介绍及yaml示例--NFS(网络数据卷)
nfs 做为 k8s 的网络存储驱动,能够知足持久存储业务的需求,支持多节点读写。下面是两个Pod同时使用一个持久性volume实例。
#建立PV apiVersion: v1 kind: PersistentVolume metadata: name: nfs-pv spec: capacity: storage: 4Gi accessModes: - ReadWriteMany nfs: server: 192.168.246.168 ##NFS服务器的ip地址 path: "/data" ##NFS服务器上的共享目录
#建立PVC apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nfs-pvc spec: accessModes: - ReadWriteMany storageClassName: "" resources: requests: storage: 3Gi
#建立Deployment apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 volumeMounts: - mountPath: "/wtf" name: datadir volumes: - name: datadir persistentVolumeClaim: claimName: nfs-pvc
更多PV和PVC实战,详见实战kubernetes持久性卷使用
Kubernetes Pod 是有生命周期的,它们能够被建立,也能够被销毁,然而一旦被销毁生命就永远结束。 经过 ReplicaSets 可以动态地建立和销毁 Pod(例如,须要进行扩缩容,或者执行 滚动升级)。 每一个 Pod 都会获取它本身的 IP 地址,即便这些 IP 地址不老是稳定可依赖的。 这会致使一个问题:在 Kubernetes 集群中,若是一组 Pod(称为 backend)为其它 Pod (称为 frontend)提供服务,那么那些 frontend 该如何发现,并链接到这组 Pod 中的哪些 backend 呢?
Kubernetes Service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种能够访问它们的策略 —— 一般称为微服务。 这一组 Pod 可以被 Service 访问到,一般是经过 Label Selector(查看下面了解,为何可能须要没有 selector 的 Service)实现的。
举个例子,考虑一个图片处理 backend,它运行了3个副本。这些副本是可互换的 —— frontend 不须要关心它们调用了哪一个 backend 副本。 然而组成这一组 backend 程序的 Pod 实际上可能会发生变化,frontend 客户端不该该也不必知道,并且也不须要跟踪这一组 backend 的状态。 Service 定义的抽象可以解耦这种关联。
对 Kubernetes 集群中的应用,Kubernetes 提供了简单的 Endpoints API,只要 Service 中的一组 Pod 发生变动,应用程序就会被更新。 对非 Kubernetes 集群中的应用,Kubernetes 提供了基于 VIP 的网桥的方式访问 Service,再由 Service 重定向到 backend Pod。
一个 Service 在 Kubernetes 中是一个 REST 对象,和 Pod 相似。 像全部的 REST 对象同样, Service 定义能够基于 POST 方式,请求 apiserver 建立新的实例。 例如,假定有一组 Pod,它们对外暴露了 9376 端口,同时还被打上 "app=MyApp" 标签。
kind: Service apiVersion: v1 metadata: name: my-service spec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 9376
上述配置将建立一个名称为 “my-service” 的 Service 对象,它会将请求代理到使用 TCP 端口 9376,而且具备标签 "app=MyApp" 的 Pod 上。 这个 Service 将被指派一个 IP 地址(一般称为 “Cluster IP”),它会被服务的代理使用(见下面)。 该 Service 的 selector 将会持续评估,处理结果将被 POST 到一个名称为 “my-service” 的 Endpoints 对象上。
须要注意的是, Service 可以将一个接收端口映射到任意的 targetPort。 默认状况下,targetPort 将被设置为与 port 字段相同的值。 可能更有趣的是,targetPort 能够是一个字符串,引用了 backend Pod 的一个端口的名称。 可是,实际指派给该端口名称的端口号,在每一个 backend Pod 中可能并不相同。 对于部署和设计 Service ,这种方式会提供更大的灵活性。 例如,能够在 backend 软件下一个版本中,修改 Pod 暴露的端口,并不会中断客户端的调用。
Kubernetes Service 可以支持 TCP 和 UDP 协议,默认 TCP 协议。
不少 Service 须要暴露多个端口。对于这种状况,Kubernetes 支持在 Service 对象中定义多个端口。 当使用多个端口时,必须给出全部的端口的名称,这样 Endpoint 就不会产生歧义,例如:
kind: Service apiVersion: v1 metadata: name: my-service spec: selector: app: MyApp ports: - name: http protocol: TCP port: 80 targetPort: 9376 - name: https protocol: TCP port: 443 targetPort: 9377
Service 抽象了该如何访问 Kubernetes Pod,但也可以抽象其它类型的 backend,例如:
根据以上的应用场景,咱们都可以定义没有selector的Service,以下:
kind: Service apiVersion: v1 metadata: name: my-service spec: ports: - protocol: TCP port: 80 targetPort: 9376
因为这个 Service 没有 selector,就不会建立相关的 Endpoints 对象。能够手动将 Service 映射到指定的 Endpoints:
kind: Endpoints apiVersion: v1 metadata: name: my-service subsets: - addresses: - ip: 10.0.0.3 ##Endpoint IP = PodIP + ContainerPort ports: - port: 9376
注意:Endpoint IP 地址不能是 loopback(127.0.0.0/8)、 link-local(169.254.0.0/16)、或者 link-local 多播(224.0.0.0/24)。
访问没有 selector 的 Service,与有 selector 的 Service 的原理相同。请求将被路由到用户定义的 Endpoint(该示例中为 10.0.0.3:9376)。
对一些应用(如 Frontend)的某些部分,可能但愿经过外部(Kubernetes 集群外部)IP 地址暴露 Service。
Kubernetes ServiceTypes 容许指定一个须要的类型的 Service,默认是 ClusterIP 类型。
Type 的取值以及行为以下:
若是设置 type 的值为 "NodePort",Kubernetes master 将从给定的配置范围内(默认:30000-32767)分配端口,每一个 Node 将从该端口(每一个 Node 上的同一端口)代理到 Service。该端口将经过 Service 的 spec.ports[*].nodePort 字段被指定。
若是须要指定的端口号,能够配置 nodePort 的值,系统将分配这个端口,不然调用 API 将会失败(好比,须要关心端口冲突的可能性)。
# pwd /data # tree -L 3 . ├── mysql │ ├── conf │ │ └── my.cnf │ └── data │ ├── auto.cnf │ ├── edusoho │ ├── ibdata1 │ ├── ib_logfile0 │ ├── ib_logfile1 │ ├── mysql │ └── performance_schema ├── nginx │ ├── conf │ │ └── nginx.conf │ ├── edusoho │ │ ├── api │ │ ├── app │ │ ├── bootstrap │ │ ├── plugins │ │ ├── src │ │ ├── vendor │ │ ├── vendor_user │ │ └── web │ └── log │ └── error.log ├── php │ ├── log │ │ └── php-fpm.log │ ├── php-fpm.conf │ ├── php.ini │ └── www.conf
apiVersion: v1 kind: Pod metadata: name: lamp-edusoho labels: app: lamp-edusoho restartPolicy: Always spec: containers: - name: nginx abels: app: lamp-nginx image: dockerhub.datagrand.com/global/nginx:v1 ports: - containerPort: 80 volumeMounts: - name: datadir mountPath: "/var/log/nginx/error.log" subPath: ./nginx/log/error.log - name: datadir mountPath: "/etc/nginx/nginx.conf" subPath: ./nginx/conf/nginx.conf - name: datadir mountPath: "/usr/share/nginx/html" subPath: ./nginx/edusoho - name: php image: dockerhub.datagrand.com/global/php:v1 ports: - containerPort: 9000 volumeMounts: - mountPath: /usr/local/php/etc/php-fpm.conf name: datadir subPath: ./php/php-fpm.conf - mountPath: /usr/local/php/etc/php-fpm.d/www.conf name: datadir subPath: ./php/www.conf - mountPath: /usr/local/php/etc/php.ini name: datadir subPath: ./php/php.ini - mountPath: /usr/local/php/var/log/php-fpm.log name: datadir subPath: ./php/log/php-fpm.log - mountPath: /usr/share/nginx/html name: datadir subPath: ./nginx/edusoho - name: mysql image: dockerhub.datagrand.com/global/mysql:5.6 ports: - containerPort: 3306 env: - name: MYSQL_ROOT_PASSWORD value: "123456" - name: MYSQL_DATABASE value: "edusoho" - name: MYSQL_USER value: "edusoho" - name: MYSQL_PASSWORD value: "edusoho" args: ['--character-set-server=utf8'] volumeMounts: - name: datadir mountPath: "/var/lib/mysql" subPath: ./mysql/data - name: datadir mountPath: "/etc/my.cnf" subPath: ./mysql/conf/my.cnf volumes: - name: datadir persistentVolumeClaim: claimName: nfs-pvc
apiVersion: v1 kind: PersistentVolume metadata: name: nfs-pv spec: capacity: storage: 4Gi accessModes: - ReadWriteMany nfs: server: 192.168.246.168 ##NFS服务器的ip地址 path: "/data" ##NFS服务器上的共享目录
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nfs-pvc spec: accessModes: - ReadWriteMany storageClassName: "" resources: requests: storage: 3Gi
apiVersion: v1 kind: Service metadata: name: edusoho labels: app: edusoho spec: type: NodePort ports: - port: 80 nodePort: 32756 selector: app: lamp-edusoho
查看Pod kubectl get po -o wide 查看Service kubectl get svc 进入容器内部某个应用,如这里的nginx kubectl exec -it lamp-edusoho -c nginx /bin/bash
http://192.168.246.168:32756/install/start-install.php 说明:这里的192.168.246.168是kubernetes的node节点IP,32756是Service中定义的nodePort。