节点信息

kubernetes 1.5.2版本

每个节点都要有:vim /etc/hosts

10.30.30.116k8s-master-116etcd
10.30.30.117k8s-master-117etcd
10.30.30.118k8s-master-118etcd
10.30.30.119k8s-produce-119
10.30.30.131k8s-produce-131  
10.30.30.135k8s-nginx-135 


 

一.etcd 集群部署

10.30.30.116,10.30.30.117,10.30.30.118:先部署etcd集群参考etcd-3.3.11 集群_码农崛起-CSDN博客_etcd集群读写

依次启动etcd服务

systemctl enable etcd;sysetmctl start etcd

[root@k8s-master-116 kubernetes]# etcdctl  member list
4fe172c7048d8e9: name=k8s-master-118 peerURLs=http://k8s-master-118:2380 clientURLs=http://k8s-master-118:2379,http://k8s-master-118:4001 isLeader=false
52a0567b30f175d3: name=k8s-master-117 peerURLs=http://k8s-master-117:2380 clientURLs=http://k8s-master-117:2379,http://k8s-master-117:4001 isLeader=false
d092ee3af52b994d: name=k8s-master-116 peerURLs=http://k8s-master-116:2380 clientURLs=http://k8s-master-116:2379,http://k8s-master-116:4001 isLeader=true

二 kubernetes master 部署

在10.30.30.116,10.30.30.117,10.30.30.118

systemctl stop firewalld.service && systemctl disable firewalld.service
sed -i "s/SELINUX=enforcing/SELINUX=disabled/"   /etc/selinux/config

yum -y install wget net-tools ntp ntpdate lrzsz

systemctl restart ntpdate.service ntpd.service && systemctl enable ntpd.service ntpdate.service
 hostnamectl --static set-hostname k8s-master-116
 hostnamectl --static set-hostname k8s-master-117
 hostnamectl --static set-hostname k8s-master-118

在 master 的虚机上,需要运行三个组件:Kubernets API Server、Kubernets Controller Manager、Kubernets Scheduler。

1. 安装 kubernetes docker ,设置开机自启动并开启服务

[root@k8s ~]#   yum -y install kubernetes-master kubernetes-client(kubectl) docker flannel

[root@k8s ~]#  systemctl start docker.service //我这里的宿主机磁盘空间不够导致docker服务起不来,清理足够的磁盘空间就可以了


1.1首先修改 /etc/kubernetes/apiserver 文件:

k8s-master-116、k8s-master-117、k8s-master-118的配置一样:

[root@k8s-master-116 kubernetes]# cat  apiserver | grep -v "#"

KUBE_API_ADDRESS="--insecure-bind-address=0.0.0.0"
KUBE_API_PORT="--port=8080"
KUBE_ETCD_SERVERS="--etcd-servers=http://etcd:2379" (是个集群)
KUBE_SERVICE_ADDRESSES="--service-cluster-ip-range=10.254.0.0/16"
KUBE_ADMISSION_CONTROL="--admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,SecurityContextDeny,ResourceQuota"
KUBE_API_ARGS="--service-node-port-range=1-65535"

1.2 接着修改  /etc/kubernetes/config 文件,

这个文件是综合文件,Kubernets API Server、Kubernets Controller Manager、Kubernets Scheduler,kube-proxy,kubelet都使用

[root@k8s-master-116 kubernetes]# cat config | grep -v "#"
KUBE_LOGTOSTDERR="--logtostderr=true"

KUBE_LOG_LEVEL="--v=0"

KUBE_ALLOW_PRIV="--allow-privileged=false"(根据情况调整为true,类似docker 里面的privileged=true)

KUBE_MASTER="--master=http://etcd:8080"(集群信息,也可以是haproxy代理地址)
不修改就看系统是否默认是--address=127.0.0.1 --leader-elect=true 状态
1.修改controller-manager和scheduler配置文件
[root@k8s-master-116 kubernetes]# cat controller-manager 
###
# The following values are used to configure the kubernetes controller-manager
# defaults from config and apiserver should be adequate
# Add your own!
#KUBE_CONTROLLER_MANAGER_ARGS="--address=127.0.0.1 --leader-elect=true"
[root@k8s-master-116 kubernetes]# cat scheduler 
###
# kubernetes scheduler config
# default config should be adequate
# Add your own!
KUBE_SCHEDULER_ARGS="--address=127.0.0.1 --leader-elect=true"
让节点有选举master leader 功能,ok master配置完成

1.3 修改 /etc/sysconfig/flanneld

[root@k8s-master-116 kubernetes]# cat /etc/sysconfig/flanneld |grep -v "#"
FLANNEL_ETCD_ENDPOINTS="http://etcd:2379"
FLANNEL_ETCD_PREFIX="/atomic.io/network"
[root@k8s-master-116 kubernetes]# etcdctl mk /atomic.io/network/config '{ "Network": "10.0.0.0/16" }' 
{ "Network": "10.0.0.0/16" }

三个节点启动

systemctl start flanneld

systemctl start docker

systemctl start kube-apiserver kube-controller-manager kube-scheduler 

1.4 查看leader信息位于哪个节点

[root@k8s-master-117 kubernetes]#  tail -f /var/log/messages
Jun 24 10:29:14 k8s-master-117 kube-controller-manager: E0624 10:29:14.539355   10807 controllermanager.go:558] Failed to start certificate controller: open /etc/kubernetes/ca/ca.pem: no such file or directory
Jun 24 10:29:14 k8s-master-117 kube-controller-manager: I0624 10:29:14.542292   10807 serviceaccounts_controller.go:120] Starting ServiceAccount controller
Jun 24 10:29:14 k8s-master-117 kube-controller-manager: I0624 10:29:14.550451   10807 garbagecollector.go:766] Garbage Collector: Initializing
Jun 24 10:29:16 k8s-master-117 kube-scheduler: I0624 10:29:16.762964   10808 leaderelection.go:247] lock is held by k8s-master-118 and has not yet expired
Jun 24 10:29:19 k8s-master-117 kube-scheduler: I0624 10:29:19.068635   10808 leaderelection.go:247] lock is held by k8s-master-118 and has not yet expired
Jun 24 10:29:21 k8s-master-117 kube-scheduler: I0624 10:29:21.745470   10808 leaderelection.go:247] lock is held by k8s-master-118 and has not yet expired
Jun 24 10:29:22 k8s-master-117 kube-apiserver: W0624 10:29:22.574708   10805 controller.go:392] Resetting endpoints for master service "kubernetes" to &TypeMeta{Kind:,APIVersion:,}
Jun 24 10:29:24 k8s-master-117 kube-controller-manager: I0624 10:29:24.550622   10807 garbagecollector.go:780] Garbage Collector: All monitored resources synced. Proceeding to collect garbage
Jun 24 10:29:24 k8s-master-117 kube-scheduler: I0624 10:29:24.731674   10808 leaderelection.go:247] lock is held by k8s-master-118 and has not yet expired
Jun 24 10:29:27 k8s-master-117 kube-scheduler: I0624 10:29:27.776649   10808 leaderelection.go:247] lock is held by k8s-master-118 and has not yet expired
Jun 24 10:29:31 k8s-master-117 kube-scheduler: I0624 10:29:31.278528   10808 leaderelection.go:247] lock is held by k8s-master-118 and has not yet expired
Jun 24 10:29:32 k8s-master-117 kube-apiserver: W0624 10:29:32.585959   10805 controller.go:392] Resetting endpoints for master service "kubernetes" to &TypeMeta{Kind:,APIVersion:,}
Jun 24 10:29:34 k8s-master-117 kube-scheduler: I0624 10:29:34.600337   10808 leaderelection.go:247] lock is held by k8s-master-118 and has not yet expired
[root@k8s-master-116 kubernetes]# kubectl -n kube-system get ep kube-controller-manager -o yaml
apiVersion: v1
kind: Endpoints
metadata:
  annotations:
    control-plane.alpha.kubernetes.io/leader: '{"holderIdentity":"k8s-master-116","leaseDurationSeconds":15,"acquireTime":"2019-06-24T02:24:14Z","renewTime":"2019-06-24T02:28:29Z","leaderTransitions":0}'
  creationTimestamp: 2019-06-24T02:24:14Z
  name: kube-controller-manager
  namespace: kube-system
  resourceVersion: "366"
  selfLink: /api/v1/namespaces/kube-system/endpoints/kube-controller-manager
  uid: 28ba9170-9627-11e9-9c2e-005056a98475
subsets: []
[root@k8s-master-116 kubernetes]# kubectl -n kube-system get ep kube-scheduler -o yaml
apiVersion: v1
kind: Endpoints
metadata:
  annotations:
    control-plane.alpha.kubernetes.io/leader: '{"holderIdentity":"k8s-master-116","leaseDurationSeconds":15,"acquireTime":"2019-06-24T02:24:14Z","renewTime":"2019-06-24T02:28:45Z","leaderTransitions":0}'
  creationTimestamp: 2019-06-24T02:24:14Z
  name: kube-scheduler
  namespace: kube-system
  resourceVersion: "387"
  selfLink: /api/v1/namespaces/kube-system/endpoints/kube-scheduler
  uid: 28b9a872-9627-11e9-9c2e-005056a98475
subsets: []

1.5 我们关掉一台集群,测试集群创建yaml看看会怎么样

[root@k8s-master-117 kubernetes]#  kubectl -n kube-system get ep kube-controller-manager -o yaml
apiVersion: v1
kind: Endpoints
metadata:
  annotations:
    control-plane.alpha.kubernetes.io/leader: '{"holderIdentity":"k8s-master-117","leaseDurationSeconds":15,"acquireTime":"2019-06-24T02:29:14Z","renewTime":"2019-06-24T02:31:05Z","leaderTransitions":0}'
  creationTimestamp: 2019-06-24T02:29:14Z
  name: kube-controller-manager
  namespace: kube-system
  resourceVersion: "573"
  selfLink: /api/v1/namespaces/kube-system/endpoints/kube-controller-manager
  uid: dbadb031-9627-11e9-9c2e-005056a98475
subsets: []
[root@k8s-master-117 kubernetes]#  kubectl -n kube-system get ep kube-scheduler -o yaml
apiVersion: v1
kind: Endpoints
metadata:
  annotations:
    control-plane.alpha.kubernetes.io/leader: '{"holderIdentity":"k8s-master-118","leaseDurationSeconds":15,"acquireTime":"2019-06-24T02:29:15Z","renewTime":"2019-06-24T02:31:12Z","leaderTransitions":0}'
  creationTimestamp: 2019-06-24T02:29:15Z
  name: kube-scheduler
  namespace: kube-system
  resourceVersion: "581"
  selfLink: /api/v1/namespaces/kube-system/endpoints/kube-scheduler
  uid: dc442ece-9627-11e9-9016-005056a91e7b
subsets: []

可以看到 controller-manager和  scheduler已转移到其他节点

三、部署 node

安装 docker,kubernetes-node ,设置开机自启动并开启服务

yum install docker kubernetes-node  flannel -y
systemctl start docker && systemctl enable docker

在 node 的虚机上,需要运行三个组件:Kubelet、Kubernets Proxy。

1.1 修改flanneld

[root@k8s-produce-119 kubernetes]# cat /etc/sysconfig/flanneld | grep -v "#"

FLANNEL_ETCD_ENDPOINTS="http://etcd:2379"

FLANNEL_ETCD_PREFIX="/atomic.io/network"

systemctl start flannled
1.2 首先修改 /etc/kubernetes/config 文件:(注意:这里配置的是etcd的地址,也就是master1/2/3的地址其中之一)

[root@k8s-produce-119 kubernetes]# cat config | grep -v "#"
KUBE_LOGTOSTDERR="--logtostderr=true"

KUBE_LOG_LEVEL="--v=0"

KUBE_ALLOW_PRIV="--allow-privileged=false"

KUBE_MASTER="--master=http://etcd:8080"(master也就是api-server的集群地址)

1.3 接着修改 /etc/kubernetes/kubelet 文件:(注:--hostname-override= 对应的node机器)

[root@k8s-produce-119 kubernetes]# cat kubelet |grep -v "#"

KUBELET_ADDRESS="--address=0.0.0.0"
KUBELET_PORT="--port=10250"

KUBELET_HOSTNAME="--hostname-override=k8s-produce-119"

KUBELET_API_SERVER="--api-servers=http://etcd:8080"

KUBELET_POD_INFRA_CONTAINER="--pod-infra-container-image=registry.access.redhat.com/rhel7/pod-infrastructure:latest"

KUBELET_ARGS="--cluster_dns=10.254.254.254 --cluster_domain=jettech.com"

 systemctl start kubelet kube-proxy

1.4. 查看集群状态

在任意一台master上查看集群中节点及节点状态:

[root@k8s ~]# kubectl get node

[root@k8s-master-116 kubernetes]# kubectl get nodes
NAME              STATUS    AGE
k8s-produce-119   Ready     2m

参考:

1、kubernetes 1.5.2原理以及集群HA部署_大坏蛋的博客-CSDN博客

k8s kubernetes 高可用https and http集群实战 HA_小刚的博客-CSDN博客

四,在kubernetes上运行一个容器之案例

1. 检查kubernetes 组件是否正常运行。

root@c720120 ~]# kubectl get cs
 NAME                 STATUS    MESSAGE              ERROR
 scheduler            Healthy   ok                  
 controller-manager   Healthy   ok                  
 etcd-0               Healthy   {"health": "true"}  
 etcd-1               Healthy   {"health": "true"}  
 etcd-2               Healthy   {"health": "true"} 
--------------------- 

2. 检查kubernetes master状态

[root@k8s-master-116 kubernetes]# kubectl cluster-info
Kubernetes master is running at http://localhost:8080

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
[root@k8s-master-116 kubernetes]# 

3.运行一个nginx的容器案例

kubectl run my-first-nginx --image=nginx --replicas=2 --port=80
deployment.apps "my-first-nginx" created

4. 查看所有的pods.

[root@k8s-master-116 kubernetes]# kubectl get pods -o wide 
NAME                              READY     STATUS    RESTARTS   AGE       IP          NODE
my-first-nginx-3504586902-905bn   1/1       Running   0          25s       10.0.10.3   k8s-produce-119
my-first-nginx-3504586902-z3rnr   1/1       Running   0          25s       10.0.10.2   k8s-produce-11

5,查看所有的deployment

[root@k8s-master-116 kubernetes]# kubectl get deployment
NAME             DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
my-first-nginx   2         2         2            2           42s
[root@k8s-master-116 kubernetes]# 

6,映射端口到外部,让用户能够访问该服务

kubectl expose deployment my-first-nginx --port=80 --type=LoadBalancer
service "my-first-nginx" exposed

7, 查看发布的服务

[root@k8s-master-116 kubernetes]# kubectl get services
NAME             CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
kubernetes       10.254.0.1      <none>        443/TCP        26m
my-first-nginx   10.254.53.226   <pending>     80:28642/TCP   22s

8,停止应用

kubectl delete deployment my-first-nginx
kubectl delete service my-first-nginx

9,可以查看创建的服务详细信息

[root@k8s-master-116 kubernetes]# kubectl describe service my-first-nginx
Name:			my-first-nginx
Namespace:		default
Labels:			run=my-first-nginx
Selector:		run=my-first-nginx
Type:			LoadBalancer
IP:			10.254.53.226
Port:			<unset>	80/TCP
NodePort:		<unset>	28642/TCP
Endpoints:		10.0.10.2:80,10.0.10.3:80
Session Affinity:	None
No events.

10,用浏览器进行校验下服务

10.30.30.116,10.30.30.117,10.30.30.118随便关机都不影响10.30.30.119:28642的访问

11.部署ingress

kubernetes service五种访问方式

1、ClusterIP

ClusterIP服务是Kuberntets的默认服务。它在集群内部生成一个服务,供集群内的其他应用访问。外部无法访问。

apiVersion: v1

kind: Service

metadata:  

  name: my-internal-service

selector:    

  app: my-app

spec:

  type: ClusterIP

  ports:  

  - name: http

    port: 80

    targetPort: 80

    protocol: TCP

这种方式也可以通过外部网络访问,不过需要使用kubernetes proxy来访问:

开启proxy

kubectl proxy --port=8080

现在可以通过Kubernetes API使用下面这个地址来访问这个服务:

http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/

何时使用这种方式?

有一些场景下,你得使用 Kubernetes 的 proxy 模式来访问你的服务:

  1. 由于某些原因,你需要调试你的服务,或者需要直接通过笔记本电脑去访问它们。
  2. 容许内部通信,展示内部仪表盘等。


这种方式要求我们运行 kubectl 作为一个未认证的用户,因此我们不能用这种方式把服务暴露到 internet 或者在生产环境使用。

2、NodePort

NodePort服务是让外部流量直接访问服务的最原始方式。NodePort,顾名思义,在所有的节点(虚拟机)上开放指定的端口,所有发送到这个端口的流量都会直接转发到服务。

apiVersion: v1

kind: Service

metadata:

 name: my-nodeport-service

selector:

 app: my-app

spec:

 type: NodePort

 ports:

 - name: http

  port: 80

  targetPort: 80

  nodePort: 30036

  protocol: TCP

NodePort服务有两个地方不同于一般的“ClusterIP”服务。首先,它的类型是“NodePort”。还有一个叫做“nodePort"的端口,能在节点上指定开放哪个端口。如果没有指定端口,它会选择一个随机端口 ( 只能使用30000–32767的端口 )

如果节点 / 虚拟机的IP地址发生变化,需要进行处理

何时使用这种方式?

这种方法有许多缺点:

  1. 每个端口只能是一种服务
  2. 端口范围只能是 30000-32767
  3. 如果节点/VM 的 IP 地址发生变化,你需要能处理这种情况。


基于以上原因,我不建议在生产环境上用这种方式暴露服务。如果你运行的服务不要求一直可用,或者对成本比较敏感,你可以使用这种方法。这样的应用的最佳例子是 demo 应用,或者某些临时应用。

3、LoadBalancer

LoadBalancer服务是发布服务到互联网的标准方式。在GKE中,它会启动一个Network Load Balancer,分配一个单独的IP地址,将所有流量转发到服务中。

何时使用这种方式?

如果你想要直接暴露服务,这就是默认方式。所有通往你指定的端口的流量都会被转发到对应的服务。它没有过滤条件,没有路由等。这意味着你几乎可以发送任何种类的流量到该服务,像 HTTP,TCP,UDP,Websocket,gRPC 或其它任意种类。

这个方式的最大缺点是每一个用 LoadBalancer 暴露的服务都会有它自己的 IP 地址,每个用到的 LoadBalancer 都需要付费,这将是非常昂贵的。

4、ExternalName类型

这种方式主要是通过CNAME实现的,在kubernetes 1.7.x以及以上才支持这种方式,例如:

这种类型其实是一个没有 selector 的 Service

apiVersion: v1

kind: Service

metadata:

  name: pinpoint

spec:

  ports:

  - protocol: TCP

    port: 80

    targetPort: 80

应用场景:

Servcie 抽象了该如何访问 Kubernetes Pod,但也能够抽象其它类型的 backend,例如:

(1)、希望在生产环境中使用外部的数据库集群,但测试环境使用自己的数据库。

(2)、希望服务指向另一个 Namespace 中或其它集群中的服务。

(3)、正在将工作负载转移到 Kubernetes 集群,和运行在 Kubernetes 集群之外的 backend。

由于这个 Service 没有 selector,就不会创建相关的 Endpoints 对象。可以手动将 Service 映射到指定的 Endpoints:(即手动创建endpoint,由于名字相同会进行自动映射)

kind: Endpoints

apiVersion: v1

metadata:

name: pinpoint

subsets:

- addresses:

     - ip: 192.168.2.58

   ports:

     - port: 80

说明:addresses后面的ip就是外接服务的访问ip,可以接多个,可以是外接服务公网IP或者可以访问的私网IP

访问没有 selector 的 Service,与有 selector 的 Service 的原理相同。请求将被路由到用户定义的 Endpoint。(上面的例子则是路由到 192.168.2.58:80)

注意:Endpoint IP 地址不能是 loopback(127.0.0.0/8)、 link-local(169.254.0.0/16)、或者 link-local 多播(224.0.0.0/24)。

ExternalName Service 是 Service 的特例,它没有 selector,也没有定义任何的端口和 Endpoint。 相反地,对于运行在集群外部的服务,它通过返回该外部服务的别名这种方式来提供服务。

kind: Service

apiVersion: v1

metadata:

  name: my-service

  namespace: prod

spec:

  type: ExternalName

  externalName: my.database.example.com

当查询主机 my-service.prod.svc.CLUSTER时,集群的 DNS 服务将返回一个值为 my.database.example.com 的 CNAME 记录。 访问这个服务的工作方式与其它的相同,唯一不同的是重定向发生在 DNS 层,而且不会进行代理或转发。

创建了没有selector的service之后,还需要手动创建endpoint才可以被实际调用。

5、Ingress

Ingress  (ingress后面需要接service作为后端应用)

Ingress实际上不是一种服务。相反,它在多个服务前面充当“智能路由”的角色,或者是集群的入口。

使用Ingress可以做很多事情,不同类型的Ingress控制器有不同的功能。

默认的GKE ingress控制器会启动一个 HTTP(S) Load Balancer,可以通过基于路径或者是基于子域名的方式路由到后端服务。例如,可以通过foo.yourdomain.com 发送任何东西到foo服务,或者是发送yourdomain.com/bar/路径下的任何东西到bar服务。

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

  name: my-ingress

spec:

  backend:

    serviceName: other

    servicePort: 8080

  rules:

  - host: foo.mydomain.com

    http:

      paths:

      - backend:

          serviceName: foo

          servicePort: 8080

  - host: mydomain.com

    http:

      paths:

      - path: /bar/*

        backend:

          serviceName: bar

          servicePort: 8080

Ingress可能是发布服务最强大的方式,同时也是最复杂的。Ingress控制器的类型很多,如 Google Cloud Load Balancer,Nginx,Contour,Istio等等。还有一些Ingress控制器插件,比如证书管理器,可以自动为服务提供SSL认证。

如果想在同一个IP地址下发布多个服务,并且这些服务使用相同的第 7 层协议(通常是 HTTP),Ingress是最有用的。如果使用原生的GCP集成,只需要支付一个负载均衡器的费用。因为Ingress是“智能”的,你可以得到很多开箱即用的特性(比如SSL、认证、路由等)。

参考kubernetes service四种访问方式 - 简书

参考Kubernetes的三种外部访问方式:NodePort、LoadBalancer 和 Ingress - DockOne.io

5.1、Ingress 简介

Ingress 组成

ingress controller
  将新加入的Ingress转化成Nginx的配置文件并使之生效
ingress服务
  将Nginx的配置抽象成一个Ingress对象,每添加一个新的服务只需写一个新的Ingress的yaml文件即可

Ingress 工作原理

1.ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化,
2.然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段nginx配置,
3.再写到nginx-ingress-control的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中,
4.然后reload一下使配置生效。以此达到域名分配置和动态更新的问题。

ingress可以实现使用nginx等开源的反向代理负载均衡器实现对外暴露服务,可以理解Ingress就是用于配置域名转发的一个东西,在nginx中就类似upstream,它与ingress-controller结合使用,通过ingress-controller监控到pod及service的变化,动态地将ingress中的转发信息写到诸如nginx、apache、haproxy等组件中实现方向代理和负载均衡。
 

1.动态配置服务
  如果按照传统方式, 当新增加一个服务时, 我们可能需要在流量入口加一个反向代理指向我们新的k8s服务. 而如果用了Ingress, 只需要配置好这个服务, 当服务启动时, 会自动注册到Ingress的中, 不需要而外的操作.
2.减少不必要的端口暴露
  配置过k8s的都清楚, 第一步是要关闭防火墙的, 主要原因是k8s的很多服务会以NodePort方式映射出去, 这样就相当于给宿主机打了很多孔, 既不安全也不优雅. 而Ingress可以避免这个问题, 除了Ingress自身服务可能需要映射出去, 其他服务都不要用NodePort方式

5.2、什么是Ingress?

从前面的学习,我们可以了解到Kubernetes暴露服务的方式目前只有三种:LoadBlancer Service、ExternalName、NodePort Service、Ingress;而我们需要将集群内服务提供外界访问就会产生以下几个问题:

5.2.1、Pod 漂移问题

Kubernetes 具有强大的副本控制能力,能保证在任意副本(Pod)挂掉时自动从其他机器启动一个新的,还可以动态扩容等,通俗地说,这个 Pod 可能在任何时刻出现在任何节点上,也可能在任何时刻死在任何节点上;那么自然随着 Pod 的创建和销毁,Pod IP 肯定会动态变化;那么如何把这个动态的 Pod IP 暴露出去?这里借助于 Kubernetes 的 Service 机制,Service 可以以标签的形式选定一组带有指定标签的 Pod,并监控和自动负载他们的 Pod IP,那么我们向外暴露只暴露 Service IP 就行了;这就是 NodePort 模式:即在每个节点上开起一个端口,然后转发到内部 Pod IP 上,如下图所示:
此时的访问方式:http://nodeip:nodeport/

5.2.2、端口管理问题

采用 NodePort 方式暴露服务面临问题是,服务一旦多起来,NodePort 在每个节点上开启的端口会及其庞大,而且难以维护;这时,我们可以能否使用一个Nginx直接对内进行转发呢?众所周知的是,Pod与Pod之间是可以互相通信的,而Pod是可以共享宿主机的网络名称空间的,也就是说当在共享网络名称空间时,Pod上所监听的就是Node上的端口。那么这又该如何实现呢?简单的实现就是使用 DaemonSet 在每个 Node 上监听 80,然后写好规则,因为 Nginx 外面绑定了宿主机 80 端口(就像 NodePort),本身又在集群内,那么向后直接转发到相应 Service IP 就行了,如下图所示:

5.2.3、域名分配及动态更新问题

从上面的方法,采用 Nginx-Pod 似乎已经解决了问题,但是其实这里面有一个很大缺陷:当每次有新服务加入又该如何修改 Nginx 配置呢??我们知道使用Nginx可以通过虚拟主机域名进行区分不同的服务,而每个服务通过upstream进行定义不同的负载均衡池,再加上location进行负载均衡的反向代理,在日常使用中只需要修改nginx.conf即可实现,那在K8S中又该如何实现这种方式的调度呢???

假设后端的服务初始服务只有ecshop,后面增加了bbs和member服务,那么又该如何将这2个服务加入到Nginx-Pod进行调度呢?总不能每次手动改或者Rolling Update 前端 Nginx Pod 吧!!此时 Ingress 出现了,如果不算上面的Nginx,Ingress 包含两大组件:Ingress Controller 和 Ingress。

Ingress 简单的理解就是你原来需要改 Nginx 配置,然后配置各种域名对应哪个 Service,现在把这个动作抽象出来,变成一个 Ingress 对象,你可以用 yaml 创建,每次不要去改 Nginx 了,直接改 yaml 然后创建/更新就行了;那么问题来了:”Nginx 该怎么处理?”

Ingress Controller 这东西就是解决 “Nginx 的处理方式” 的;Ingress Controoler 通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化,然后读取他,按照他自己模板生成一段 Nginx 配置,再写到 Nginx Pod 里,最后 reload 一下,工作流程如下图:

实际上Ingress也是Kubernetes API的标准资源类型之一,它其实就是一组基于DNS名称(host)或URL路径把请求转发到指定的Service资源的规则。用于将集群外部的请求流量转发到集群内部完成的服务发布。我们需要明白的是,Ingress资源自身不能进行“流量穿透”,仅仅是一组规则的集合,这些集合规则还需要其他功能的辅助,比如监听某套接字,然后根据这些规则的匹配进行路由转发,这些能够为Ingress资源监听套接字并将流量转发的组件就是Ingress Controller。

PS:Ingress 控制器不同于Deployment 控制器的是,Ingress控制器不直接运行为kube-controller-manager的一部分,它仅仅是Kubernetes集群的一个附件,类似于CoreDNS,需要在集群上单独部署。

参考Kubernetes学习之路(十五)之Ingress和Ingress Controller - 烟雨浮华 - 博客园

cat default-backend.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: default-http-backend
  labels:
    k8s-app: default-http-backend
  namespace: kube-system
spec:
  replicas: 1
  template:
    metadata:
      labels:
        k8s-app: default-http-backend
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: default-http-backend
        image: docker.io/cdchen/defaultbackend:1.0
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 30
          timeoutSeconds: 5
        ports:
        - containerPort: 8080
        resources:
          limits:
            cpu: 10m
            memory: 20Mi
          requests:
            cpu: 10m
            memory: 20Mi
      nodeSelector:
        kubernetes.io/hostname: k8s-nginx-135
---
apiVersion: v1
kind: Service
metadata:
  name: default-http-backend
  namespace: kube-system
  labels:
    k8s-app: default-http-backend
spec:
  ports:
  - port: 80
    targetPort: 8080
  selector:
    k8s-app: default-http-backend

cat nginx-ingress-controller.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx-ingress-controller
  labels:
    k8s-app: nginx-ingress-controller
  namespace: kube-system
spec:
  replicas: 1
  template:
    metadata:
      labels:
        k8s-app: nginx-ingress-controller
      annotations:
        prometheus.io/port: '10254'
        prometheus.io/scrape: 'true'
    spec:
      hostNetwork: true
      terminationGracePeriodSeconds: 60
      containers:
      - image: registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:0.9.0-beta.10
        name: nginx-ingress-controller
        readinessProbe:
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
        livenessProbe:
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          timeoutSeconds: 1
        ports:
        - containerPort: 80
          hostPort: 80
        - containerPort: 443
          hostPort: 443
        env:
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: POD_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
        args:
        - /nginx-ingress-controller
        - --default-backend-service=$(POD_NAMESPACE)/default-http-backend
        - --apiserver-host=http://10.30.30.116:8080
      nodeSelector:
        kubernetes.io/hostname: k8s-nginx-135

使用 3个应用 三个ingress规则 一个对外提供的统一访问入口(可选service-nodeport.yaml)

1)cat kubernetes-dashboard.yaml

kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  labels:
    app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kubernetes-dashboard
  template:
    metadata:
      labels:
        app: kubernetes-dashboard
      annotations:
        scheduler.alpha.kubernetes.io/tolerations: |
          [
            {
              "key": "dedicated",
              "operator": "Equal",
              "value": "master",
              "effect": "NoSchedule"
            }
          ]
    spec:
      containers:
      - name: kubernetes-dashboard
        image: hub.c.163.com/allan1991/kubernetes-dashboard-amd64:v1.5.1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 9090
          protocol: TCP
        args:
          - --apiserver-host=http://10.30.30.116:8080
        livenessProbe:
          httpGet:
            path: /
            port: 9090
          initialDelaySeconds: 30
          timeoutSeconds: 30
---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kube-system
spec:
  ports:
  - port: 80
    targetPort: 9090
  selector:
    app: kubernetes-dashboard

2)cat jenkins-app.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: jenkins
  namespace: kube-system
  labels:
    k8s-app: jenkins
spec:
  replicas: 1
  selector:
    matchLabels:
      k8s-app: jenkins
  template:
    metadata:
      labels:
        k8s-app: jenkins
    spec:
      containers:
      - name: jenkins
        image: hub.c.163.com/library/jenkins:latest
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - name: jenkins-home
          mountPath: /var/jenkins_home
        - name: maven-repository
          mountPath: /opt/maven/repository
        - name: docker
          mountPath: /usr/bin/docker
        - name: docker-sock
          mountPath: /var/run/docker.sock
        ports:
        - containerPort: 8080
        - containerPort: 50000
      volumes:
        - name: jenkins-home
          hostPath:
            path: /ceph/jenkins_home
        - name: maven-repository
          hostPath:
            path: /ceph/maven/repository
        - name: docker
          hostPath:
            path: /usr/bin/docker
        - name: docker-sock
          hostPath:
            path: /var/run/docker.sock
      nodeSelector:
        kubernetes.io/hostname: k8s-produce-131
---
kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: jenkins
  name: jenkins
  namespace: kube-system
  annotations:
    prometheus.io/scrape: 'true'
spec:
  ports:
    - name: jenkins
      port: 80
      nodePort: 31888
      targetPort: 8080
      protocol: TCP
    - name: jenkins-agent
      port: 50000
      targetPort: 50000
  type: LoadBalancer
  selector:
    k8s-app: jenkins

3)cat tomcat-demo.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: tomcat-deploy
  #namespace: default
  namespace: kube-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: tomcat
      release: canary
  template:
    metadata:
      labels:
        app: tomcat
        release: canary
    spec:
      containers:
      - name: tomcat
        image: tomcat:8.5.34-jre8-alpine   
        ports:
        - name: http
          containerPort: 8080
          name: ajp
          containerPort: 8009

---

kind: Service
apiVersion: v1
metadata:
  name: tomcat
  #namespace: default
  namespace: kube-system
spec:
  selector:
    app: tomcat
    release: canary
  #type: NodePort
  ports:
  - name: http
    targetPort: 8080
    #nodePort: 38080
    port: 8080
  - name: ajp
    targetPort: 8009
    #nodePort: 38009
    port: 8009
---

cat jenkins-ingress.yml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: jenkins-ingress
  #namespace: default
  namespace: kube-system(要和服务的命名空间一致)
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: /
    #nginx.ingress.kubernetes.io/configuration-snippet: |
       #rewrite /(wubo*) login/wubo break;
       #if ($request_uri = '/?%login') { rewrite /(.*) login/wubo break; }
spec:
  #tls:
  #- hosts:
  #  secretName: ding-ingress-secret
  rules:
  - host: ingress.jettech.com
    http:
      paths:
      - path: /login
        backend:
          serviceName: jenkins
          servicePort: 80(要和port端口一致,port是集群内部服务器之间访问的端口)
      - path: /
        backend:
          serviceName: kubernetes-dashboard
          servicePort: 80
  - host: ingress.tomcat.com
    http:
      paths:
      - path: /
        backend:
          serviceName: tomcat
          servicePort: 8080
service-nodeport.yaml 这个是对 nginx-ingress-controller做个对外服务统一访问  #对外提供服务,如果不需要可以不下载
apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: kube-system
  labels:
    k8s-app: nginx-ingress-controller
spec:
  type: NodePort
  ports:
    - name: http
      port: 80
      targetPort: 80
      protocol: TCP
      nodePort: 32080
    - name: https
      port: 443
      targetPort: 443
      protocol: TCP
      nodePort: 32443
  selector:
    k8s-app: nginx-ingress-controller

---

此时有可以通过ingress.jettech.com:32080进行访问,也可以直接ingress.jettech.com访问(直接访问就是没有走service-nodeport.yaml 统一入口)

参考

kubernetes学习笔记之七: Ingress-nginx 部署使用 - 百衲本 - 博客园

Kubernetes学习之路(十五)之Ingress和Ingress Controller - 烟雨浮华 - 博客园

5.2.4总结

从前面的部署过程中,可以再次进行总结部署的流程如下:
①下载Ingress-controller相关的YAML文件,并给Ingress-controller创建独立的名称空间;
②部署后端的服务,如myapp,并通过service进行暴露;
③部署Ingress-controller的service,以实现接入集群外部流量;
④部署Ingress,进行定义规则,使Ingress-controller和后端服务的Pod组进行关联。
本次部署后的说明图如下:

5.2.5 构建TLS站点

(1)准备证书

[root@k8s-master ingress]# openssl genrsa -out tls.key 2048 
Generating RSA private key, 2048 bit long modulus
.......+++
.......................+++
e is 65537 (0x10001)

[root@k8s-master ingress]# openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=ingress.tomcat.com  #注意域名要和服务的域名一致 

(2)生成secret

[root@k8s-master ingress]# kubectl create secret tls tomcat-ingress-secret --cert=tls.crt --key=tls.key -n kube-system
secret/tomcat-ingress-secret created
[root@k8s-master-118 ~]#  kubectl get secret -n kube-system
NAME                    TYPE                DATA      AGE
tomcat-ingress-secret   kubernetes.io/tls   2         5m
[root@k8s-master-118 ~]#  kubectl describe secret -n kube-system
Name:		tomcat-ingress-secret
Namespace:	kube-system
Labels:		<none>
Annotations:	<none>

Type:	kubernetes.io/tls

Data
====
tls.crt:	1298 bytes
tls.key:	1679 bytes

(3)创建ingress

cat jenkins-ingress.yml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: jenkins-ingress
  #namespace: default
  namespace: kube-system
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: /
    #nginx.ingress.kubernetes.io/configuration-snippet: |
       #rewrite /(wubo*) login/wubo break;
       #if ($request_uri = '/?%login') { rewrite /(.*) login/wubo break; }
spec:
  tls:
  - hosts:
    - ingress.tomcat.com   #与secret证书的域名需要保持一致,也要和下面的-host 保持一致 三致一致 
    secretName: tomcat-ingress-secret  #secret证书的名称
  rules:
  - host: ingress.jettech.com
    http:
      paths:
      - path: /login
        backend:
          serviceName: jenkins
          servicePort: 80
      - path: /
        backend:
          serviceName: kubernetes-dashboard
          servicePort: 80
  - host: ingress.tomcat.com
    http:
      paths:
      - path: /
        backend:
          serviceName: tomcat
          servicePort: 8080

https://ingress.tomcat.com

https://ingress.tomcat.com:32443

参考Kubernetes学习之路(十五)之Ingress和Ingress Controller - 烟雨浮华 - 博客园

Ingress | Kubernetes

ingress-nginx/index.md at nginx-0.20.0 · kubernetes/ingress-nginx · GitHub

Installation Guide - NGINX Ingress Controller

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐