要资料 文章 文库 Lib 视频 Code iProcess 课程 认证 咨询 工具 火云堂 讲座吧   成长之路  
会员   
 
追随技术信仰

随时听讲座
每天看新闻
 
 

Kubernetes教程
Kubernetes概述
Kubernetes设计架构
kubernetes设计理念
创建Kubernetes集群
基于Docker本地运行Kubernetes
使用Vagrant
本地运行Kubrenetes v1.0
Google Computer Engine入门
AWS EC2快速入门
在Azure上使用CoreOS和Weave的 Kubernetes
从零开始k8s
CoreOS部署Kubernetes集群
CloudStack部署Kubernetes集群
vSphere部署Kubernetes集群
Ferdora部署Kubernetes集群
CentOS部署Kubernetes集群
Ubuntu物理节点上部署Kubernets集群
Mesos部署Kubernetes集群
Kubernetes用户指南:应用程序管理
名词解释 Pods
名词解释 Labels
名词解释:Namespace
名词解释 Replication Controller
名词解释:Node
名词解释:ReplicaSets
名词解释 Services
名词解释 Volumes
名词解释:PV/PVC/StorageClass
名称解释:Deployment
名词解释:Secret
名词解释:StatefulSet
名词解释:DaemonSet
名词解释:Service Account
名词解释:CronJob
名词解释:Job
名词解释:Security Context和PSP
名词解释:Resource Quotas
名词解释:Network Policy
名词解释:Ingress
名词解释:ThirdPartyResources
名词解释:ConfigMap
名词解释:PodPreset
配置Kubernetes
管理应用:部署持续运行的应用
Horizontal Pod Autoscaling
管理应用:连接应用
管理应用: 在生产环境中使用Pods和容器
Kubernetes UI
Kube-API Server
授权插件
认证插件
API Server端口配置
Admission Controller
Service Accounts集群管理指南
使用Kubernetes在云上原生部署cassandra
 
 

管理应用:连接应用
 
26 次浏览
5次  
 捐助

Kubernetes容器连接模型

既然已经有了一个可持续运行的、可复制的应用,现在就可以在网络中将它暴露出来了。在讨论Kubernetes的网络连接方式之前,很值得和Docker的常规网络连接方式做个对比。

Dokcer默认使用私有网络连接方式,所以只有在同一台物理机器上的容器之前才可以通信。为了能让Docker容器可以跨节点通信,必须要给机器的IP地址分配端口号,这个端口之后会被用来转发或者路由给容器。很明显,这意味着容器要么很小心地协调使用端口,要么有动态分配地端口。

在一定的规模下,为多个开发者协调端口号非常困难。这也会把集群级别的问题暴露给用户,这是在用户的控制之外的。Kubernetes假定pods之间是可以通信的,不管它们落到哪个主机上。我们给每个pod指定集群私有的IP地址(cluster-private-IP address),所以不需要显示地创建pod之间的链接,也不需要映射容器的端口到主机的端口。这意味着pod里的容器可以在本机(localhost)上访问各自的端口,而且在没有NAT的情况下,集群中所有的pod也可以互相可见的。本文剩下的内容将会详细阐述如何在这样的网络模型中运行可靠的服务。

这个指南中用了一个简单的nginx服务来演示验证这个概念(proof of concept)。同样的原理也在一个更完整的Jenkins CI 应用中体现了。

在集群中暴露Pod

在前面的例子中已经演示过,让我们把注意力集中在网络的视角在来一次。创建一个nginx的 Pod ,请注意它定义了容器的端口:

$ cat nginxrc.yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: my-nginx
spec:
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80

这使得它从集群中的任一节点都可以被访问到。检查一下供pod运行的节点:

$ kubectl create -f ./nginxrc.yaml
$ kubectl get pods -l app=nginx -o wide
my-nginx-6isf4 1/1 Running 0 2h e2e-test-beeps-minion-93ly
my-nginx-t26zt 1/1 Running 0 2h e2e-test-beeps-minion-93ly

检查pod的IP地址:

$ kubectl get pods -l app=nginx -o json | grep podIP
"podIP": "10.245.0.15",
"podIP": "10.245.0.14",

你应该可以ssh到集群里的任何一个节点,而且用curl也能够访问这两个IP。要注意的是容器并没有用节点的80端口,也没用任何特殊的会把流量路由到pod的NAT规则。这意味着你可以在同一个节点上用同样的 containerPort 配置运行多个nginx pod,而且通过IP就可以在其他pod或者集群里的其他节点访问它们。和Docker类似,端口也可以在节点的网络接口中发布出来,但是在Kubernetes的这种网络模型下,这样的需求从根本上减少了。

创建Service

现在我们有了运行态的nginx,它们运行在一个水平的,集群范围的地址空间内。理论上,我们已经可以和这些pod直接交互了,但是如果一个节点死掉了会发生什么?它里面的Pod也会死掉,然后Replication Controller会创建一个新的Pod,但是IP是不一样的。这就是Service可以解决的问题。

Kubernetes Service是对在集群中某处运行的一系列Pod的逻辑集合的抽象定义,这些Pod提供的功能是一样的。每个Service被创建的时候会被分配一个唯一的IP地址(也叫 clusterIP )。这个地址和Service绑定,只要Service活着就不会改变。Pod可以配置成和Service交互,并且知道和Service的通信会被自动地负载均衡到Service成员中的某个Pod。

可以用下面的yaml为两个nginx副本创建一个Service:

$ cat nginxsvc.yaml
apiVersion: v1
kind: Service
metadata:
name: nginxsvc
labels:
app: nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
app: nginx

这个定义会创建一个Service,这个Service会把带有app=nginx Label的Pod的TCP 80端口暴露到Service的抽象端口(targetPort:是容器可以接收流量的端口,port:是Service的抽象端口,可以是除用来访问Service的端口之外的任何端口)。在Service定义中支持的所有的域可以在Service API 对象中查看。

查看Service:

$ kubectl get svc
NAME LABELS SELECTOR IP(S) PORT(S)
nginxsvc app=nginx app=nginx 10.0.116.146 80/TCP

在前面提到过,Service是由一组Pod支撑的。这些Pod通过endpoints暴露出来。Service会持续评估Selector,并把结果发送给Endpoint对象(也叫做nginxsvc)。当一个Pod死了之后,它就会被自动地从Endpoint里面删掉,能够匹配Service的Selector的新Pod会被自动加到Endpoint里。检查Endpoint的时候也会看到IP和前一步里创建的Pod是一样的:

$ kubectl describe svc nginxsvc
Name: nginxsvc
Namespace: default
Labels: app=nginx
Selector: app=nginx
Type: ClusterIP
IP: 10.0.116.146
Port: <unnamed> 80/TCP
Endpoints: 10.245.0.14:80,10.245.0.15:80
Session Affinity: None
No events.

$ kubectl get ep
NAME ENDPOINTS
nginxsvc 10.245.0.14:80,10.245.0.15:80


现在你应该可以从集群里的任一节点上用curl命令访问10.0.116.146:80上的nginx Service了。要注意的是Service的IP完全是虚拟的,跟物理网络没有关系。

访问Service

Kubernetes支持两种主要的模式来发现Service:环境变量和DNS。环境变量在安装之后就可以直接使用,DNS模式需要kube-dns 集群插件。

环境变量

当一个Pod在某个节点上运行的时候, kubelet 为每个活跃的Service添加一系列的环境变量。这会引入环境变量排序的问题。想知道为什么,检查一下运行中的nginx Pod的环境:

$ kubectl exec my-nginx-6isf4 -- printenv | grep SERVICE
KUBERNETES_SERVICE_HOST=10.0.0.1
KUBERNETES_SERVICE_PORT=443

注意这里并没有提到Service,这是因为这些副本是在Service之前创建的。这样做的另一个缺点是,调度器也许会把两个Pod放到相同的机器上,如果机器出问题,整个Service就不工作了。正确的方式是把这两个Pod杀掉,然后等Replication Controller重新创建它们。现在Service是在Pod副本之前存在了,因此Service获得了调度器级别的Pod扩散能力(只要所有的节点的容量是一样的),而且环境变量也是正确的:

$ kubectl scale rc my-nginx --replicas=0; kubectl scale rc my-nginx --replicas=2;
$ kubectl get pods -l app=nginx -o wide
NAME READY STATUS RESTARTS AGE NODE
my-nginx-5j8ok 1/1 Running 0 2m node1
my-nginx-90vaf 1/1 Running 0 2m node2

$ kubectl exec my-nginx-5j8ok -- printenv | grep SERVICE
KUBERNETES_SERVICE_PORT=443
NGINXSVC_SERVICE_HOST=10.0.116.146
KUBERNETES_SERVICE_HOST=10.0.0.1
NGINXSVC_SERVICE_PORT=80


DNS

Kubernetes提供了一个DNS集群插件Service,这个Service使用 skydns 自动给其他Service分配DNS。可以用下面的命令检查它是否在集群中运行:

If it isn’t running, you can enable it. The rest of this sectionwill assume you have a Service with a long lived ip (nginxsvc), and a dns server that hasassigned a name to that ip (the kube-dns cluster addon), so you can talk to the Service fromany pod in your cluster using standard methods (e.g. gethostbyname). Let’s create anotherpod to test this:

$ cat curlpod.yaml
apiVersion: v1
kind: Pod
metadata:
name: curlpod
spec:
containers:
- image: radial/busyboxplus:curl
command:
- sleep
- "3600"
imagePullPolicy: IfNotPresent
name: curlcontainer
restartPolicy: Always

And perform a lookup of the nginx Service

$ kubectl create -f ./curlpod.yaml
default/curlpod
$ kubectl get pods curlpod
NAME READY STATUS RESTARTS AGE
curlpod 1/1 Running 0 18s
$ kubectl exec curlpod -- nslookup nginxsvc
Server: 10.0.0.10
Address 1: 10.0.0.10
Name: nginxsvc
Address 1: 10.0.116.146

Securing the Service

Till now we have only accessed the nginx server from within the cluster. Before exposing theService to the internet, you want to make sure the communication channel is secure. Forthis, you will need:

Self signed certificates for https (unless you already have an identitiy certificate)

An nginx server configured to use the cretificates

A secret that makes the certificates accessible to pods

You can acquire all these from the nginx https example, in short:

$ make keys secret KEY=/tmp/nginx.key CERT=/tmp/nginx.crt SECRET=/tmp/secret.json
$ kubectl create -f /tmp/secret.json
secrets/nginxsecret
$ kubectl get secrets
NAME TYPE DATA
default-token-il9rc kubernetes.io/service-account-token 1
nginxsecret Opaque

Now modify your nginx replicas to start a https server using the certificate in the secret, andthe Service, to expose both ports (80 and 443):


您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码: 验证码,看不清楚?请点击刷新验证码 必填



26 次浏览
5次
 捐助
 

每天2个文档/视频
扫描微信二维码订阅
订阅技术月刊
获得每月300个技术资源
 
 

关于我们 | 联系我们 | 京ICP备10020922号 京公海网安备110108001071号