k8s初级班day2

第7章:深入理解常用控制器

7.1 Pod与controller的关系

  • controllers:在集群上管理和运行容器的对象。有时也称为工作负载(workload)

  • 通过label-selector相关联,如下图所示。

  • Pod通过控制器实现应用的运维,如伸缩,滚动升级等

7.2 无状态应用部署控制器 Deployment

Deployment功能:

  • 部署无状态应用(无状态应用简单来讲,就是Pod可以漂移任意节点,而不用考虑数据和IP变化)

  • 管理Pod和ReplicaSet(副本数量管理控制器)

  • 具有上线部署、副本设定、滚动升级、回滚等功能

  • 提供声明式更新,例如只更新一个新的Image

应用场景:Web服务,微服务

下图是Deployment 标准YAML,通过标签与Pod关联。

使用YAML部署一个java应用:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3    # 设置3个副本
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - image: lizhenliang/java-demo
        name: java

将这个java应用暴露到集群外部访问:

apiVersion: v1
kind: Service
metadata:
  labels:
    app: web
  name: web
spec:
  ports:
  - port: 80             # 集群内容访问应用端口
    protocol: TCP
    targetPort: 8080     # 容器镜像端口
    nodePort: 30008      # 对外暴露的端口
  selector:
    app: web
  type: NodePort

查看资源:

kubectl get pods,svc
NAME                       READY   STATUS    RESTARTS   AGE
pod/web-7f9c858899-dcqwb   1/1     Running   0          18s
pod/web-7f9c858899-q26bj   1/1     Running   0          18s
pod/web-7f9c858899-wg287   1/1     Running   0          48s

NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
service/kubernetes   ClusterIP   10.1.0.1      <none>        443/TCP        5m55s
service/web          NodePort    10.1.157.27   <none>        80:30008/TCP   48s

浏览器输入:http://NodeIP:30008 即可访问到该应用。

升级项目,即更新最新镜像版本,这里换一个nginx镜像为例:
kubectl set image deployment/web nginx=nginx:1.15
kubectl rollout status deployment/web # 查看升级状态

如果该版本发布失败想回滚到上一个版本可以执行:
kubectl rollout undo deployment/web   # 回滚最新版本

也可以回滚到指定发布记录:
kubectl rollout history deployment/web  # 查看发布记录
kubectl rollout undo deployment/web --revision=2  # 回滚指定版本

扩容/缩容:
kubectl scale deployment nginx-deployment --replicas=5 
--replicas设置比现在值大就是扩容,反之就是缩容。

kubectl set image 会触发滚动更新,即分批升级Pod。

滚动更新原理其实很简单,利用新旧两个replicaset,例如副本是3个,首先Scale Up增加新RS副本数量为1,准备就绪后,Scale Down减少旧RS副本数量为2,以此类推,逐渐替代,最终旧RS副本数量为0,新RS副本数量为3,完成本次更新。这个过程可通过kubectl describe deployment web看到。

7.3 守护进程控制器 DaemonSet

DaemonSet功能:

  • 在每一个Node上运行一个Pod

  • 新加入的Node也同样会自动运行一个Pod

应用场景:Agent,例如监控采集工具,日志采集工具

7.4 批处理 Job & CronJob

Job:一次性执行

应用场景:离线数据处理,视频解码等业务

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    spec:
      containers:
      - name: pi
        image: perl
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never   # 作业失败后会不再尝试创建新的Pod
  backoffLimit: 4   # .spec.backoffLimit字段限制重试次数。默认情况下,这个字段默认值是6。

上述示例中将π计算到2000个位置并将其打印出来。完成大约需要10秒。

查看任务:

kubectl get pods,job 

CronJob:定时任务,像Linux的Crontab一样。

应用场景:通知,备份

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: hello
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: hello
            image: busybox
            args:
            - /bin/sh
            - -c
            - date; echo Hello from the Kubernetes cluster
          restartPolicy: OnFailure  # 作业失败并返回状态码非0时,尝试创建新的Pod运行任务

上述示例中将每分钟打印一次Hello。

查看任务:

kubectl get pods,cronjob

第8章:深入理解Service

8.1 Service存在的意义

  • 防止Pod失联(服务发现)

  • 定义一组Pod的访问策略(负载均衡)

8.2 Pod与Service的关系

  • 通过label-selector相关联

  • 通过Service实现Pod的负载均衡( TCP/UDP 4层)

8.2 Service三种类型

  • ClusterIP:集群内部使用,默认**,**分配一个稳定的IP地址,即VIP,只能在集群内部访问(同Namespace内的Pod)。

  • NodePort:对外暴露应用。在每个节点上启用一个端口来暴露服务,可以在集群外部访问。也会分配一个稳定内部集群IP地址。访问地址::

  • LoadBalancer:对外暴露应用,适用公有云、与NodePort类似,在每个节点上启用一个端口来暴露服务。除此之外,Kubernetes会请求底层云平台上的负载均衡器,将每个Node([NodeIP]:[NodePort])作为后端添加进去。

8.3 Service代理模式

Iptables:

  • 灵活,功能强大

  • 规则遍历匹配和更新,呈线性时延

IPVS:

  • 工作在内核态,有更好的性能

  • 调度算法丰富:rr,wrr,lc,wlc,ip hash…

kubectl get cm -n kube-system
kubectl edit cm kube-proxy -n kube-system  

Service DNS名称

DNS服务监视Kubernetes API,为每一个Service创建DNS记录用于域名解析。

ClusterIP A记录格式:..svc.cluster.local

示例:my-svc.my-namespace.svc.cluster.local

小结

  1. 采用NodePort对外暴露应用,前面加一个LB实现统一访问入口

  2. 优先使用IPVS代理模式

  3. 集群内应用采用DNS名称访问

第9章:Ingress

8.1 Ingress为弥补NodePort不足而生

NodePort存在的不足:

  • 一个端口只能一个服务使用,端口需提前规划

  • 只支持4层负载均衡

8.2 Pod与Ingress的关系

  • 通过Service相关联

  • 通过Ingress Controller实现Pod的负载均衡

    • 支持TCP/UDP 4层和HTTP 7层

8.3 Ingress Controller

为了使Ingress资源正常工作,集群必须运行一个Ingress Controller(负载均衡实现)。

所以要想通过ingress暴露你的应用,大致分为两步:

  1. 部署Ingress Controller

  2. 创建Ingress规则

整体流程如下:

Ingress Controller有很多实现,我们这里采用官方维护的Nginx控制器。

部署文档:https😕/github.com/kubernetes/ingress-nginx/blob/master/docs/deploy/index.md

注意事项:

  • 镜像地址修改成国内的:lizhenliang/nginx-ingress-controller:0.20.0

  • 使用宿主机网络:hostNetwork: true

# kubectl apply -f ingress-controller.yaml
# kubectl get pods -n ingress-nginx
NAME                             READY   STATUS    RESTARTS   AGE
nginx-ingress-controller-5r4wg   1/1     Running   0          13s
nginx-ingress-controller-x7xdf   1/1     Running   0          13s

此时在任意Node上就可以看到该控制监听的80和443端口:

# netstat -natp |egrep ":80|:443"
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      104750/nginx: maste 
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      104750/nginx: maste 

80和443端口就是接收来自外部访问集群中应用流量,转发对应的Pod上。

其他主流控制器:

Traefik: HTTP反向代理、负载均衡工具

Istio:服务治理,控制入口流量

8.4 Ingress

接下来,就可以创建ingress规则了。

在ingress里有三个必要字段:

  • host:访问该应用的域名,也就是域名解析
  • serverName:应用的service名称
  • serverPort:service端口

1、HTTP访问

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: example-ingress
spec:
  rules:
  - host: example.ctnrs.com
    http:
      paths:
      - path: /
        backend:
          serviceName: web
          servicePort: 80

生产环境:example.ctnrs.com 域名是在你购买域名的运营商上进行解析,A记录值为K8S Node的公网IP(该Node必须运行了Ingress controller)。

测试环境:可以绑定hosts模拟域名解析(“C:\Windows\System32\drivers\etc\hosts”),对应IP是K8S Node的内网IP。例如:

192.168.31.62 example.ctnrs.com

2、HTTPS访问

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: tls-example-ingress
spec:
  tls:
  - hosts:
    - sslexample.ctnrs.com
    secretName: example-ctnrs-com
  rules:
    - host: sslexample.ctnrs.com
      http:
        paths:
        - path: /
          backend:
            serviceName: web
            servicePort: 80

里面用到了secret名为secret-tls,用于保存https证书。

[root@k8s-master1 ~]# cat cfssl.sh 
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
chmod +x cfssl*
mv cfssl_linux-amd64 /usr/bin/cfssl
mv cfssljson_linux-amd64 /usr/bin/cfssljson
mv cfssl-certinfo_linux-amd64 /usr/bin/cfssl-certinfo

[root@k8s-master1 ~]# cat cert.sh 
cat > ca-config.json <<EOF
{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "kubernetes": {
         "expiry": "87600h",
         "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ]
      }
    }
  }
}
EOF

cat > ca-csr.json <<EOF
{
    "CN": "kubernetes",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "Beijing",
            "ST": "Beijing"
        }
    ]
}
EOF

cfssl gencert -initca ca-csr.json | cfssljson -bare ca -

cat > binglei.hou.com-csr.json <<EOF
{
  "CN": "binglei.hou.com",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "L": "BeiJing",
      "ST": "BeiJing"
    }
  ]
}
EOF

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes binglei.hou.com-csr.json | cfssljson -bare binglei.hou.com 

kubectl create secret tls binglei.hou.com --cert=binglei.hou.com.pem --key=binglei.hou.com-key.pem

这里使用cfssl工具自签证书用于测试,先下载cfssl工具:

curl -s -L -o /usr/local/bin/cfssl https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
curl -s -L -o /usr/local/bin/cfssljson https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
curl -s -L -o /usr/local/bin/cfssl-certinfo https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
chmod +x /usr/local/bin/cfssl*

执行课件中的certs.sh脚本,生成证书:

ls *pem
ca.pem ca-key.pem example.ctnrs.com.pem example.ctrnrs.com-key.pem

将证书保存在secret里:

kubectl create secret tls example-ctnrs-com --cert=example.ctnrs.com.pem --key=example.ctrnrs.com-key.pem

这样,ingress就能通过secret名称拿到要用的证书了。

然后绑定本地hosts,就可以https访问了:https://example-ctnrs-com

3、根据URL路由到多个服务

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: url-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: foobar.ctnrs.com
    http:
      paths:
      - path: /foo
        backend:
          serviceName: service1
          servicePort: 80
  - host: foobar.ctnrs.com
    http:
      paths:
      - path: /bar
        backend:
          serviceName: service2
          servicePort: 80

工作流程:

foobar.ctnrs.com -> 178.91.123.132 -> / foo    service1:80
                                      / bar    service2:80

4、基于名称的虚拟主机

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: name-virtual-host-ingress
spec:
  rules:
  - host: foo.ctnrs.com
    http:
      paths:
      - backend:
          serviceName: service1
          servicePort: 80
  - host: bar.ctnrs.com
    http:
      paths:
      - backend:
          serviceName: service2
          servicePort: 80

工作流程:

foo.bar.com --|                 |-> service1:80
              | 178.91.123.132  |
bar.foo.com --|                 |-> service2:80

8.5 Annotations对Ingress个性化配置

参考文档 :https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/annotations.md

HTTP:配置Nginx常用参数

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
     kubernetes.io/ingress.class: "nginx“
     nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
     nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
     nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
     nginx.ingress.kubernetes.io/proxy-body-size: "10m"
spec:
  rules:
  - host: example.ctnrs.com
    http:
      paths:
      - path: /
        backend:
          serviceName: web
          servicePort: 80

HTTPS:禁止访问HTTP强制跳转到HTTPS(默认开启)

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: tls-example-ingress
  annotations:
    kubernetes.io/ingress.class: "nginx“
    nginx.ingress.kubernetes.io/ssl-redirect: 'false'
spec:
  tls:
  - hosts:
    - sslexample.ctnrs.com
    secretName: secret-tls
  rules:
    - host: sslexample.ctnrs.com
      http:
        paths:
        - path: /
          backend:
            serviceName: web
            servicePort: 80

8.6 Ingress Controller高可用方案

如果域名只解析到一台Ingress controller,是存在单点的,挂了就不能提供服务了。这就需要具备高可用,有两种常见方案:

左边:双机热备,选择两台Node专门跑Ingress controller,然后通过keepalived对其做主备。用户通过VIP访问。

右边:高可用集群(推荐),前面加一个负载均衡器,转发请求到后端多台Ingress controller。

第10章:管理应用程序配置

10.1 secret

secret加密数据并存放Etcd中,让Pod的容器以挂载Volume方式访问。

应用场景:凭据

Pod使用secret两种方式:

  • 变量注入

  • 挂载

例如:创建一个secret用于保存应用程序用到的用户名和密码

echo -n 'admin' | base64
YWRtaW4=
echo -n '1f2d1e2e67df' | base64
MWYyZDFlMmU2N2Rm

创建secret:

apiVersion: v1
kind: Secret
metadata:
  name: mysecret
type: Opaque
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm

变量注入方式在Pod中使用secret:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: nginx
    image: nginx
    env:
      - name: SECRET_USERNAME
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: username
      - name: SECRET_PASSWORD
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: password

进入到Pod中测试是否传入变量:

# kubectl exec -it mypod bash
# echo $SECRET_USERNAME
admin
# echo $SECRET_PASSWORD
1f2d1e2e67df

数据挂载方式在Pod中使用secret:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: nginx
    image: nginx
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: mysecret

进入到Pod中测试是否写入文件:

# kubectl exec -it mypod bash
#cat /etc/foo/username
admin
# cat /etc/foo/password
1f2d1e2e67df

如果你的应用程序使用secret,应遵循Pod获取该数据的方式。

10.2 configmap

与Secret类似,区别在于ConfigMap保存的是不需要加密配置信息。

应用场景:应用配置

例如:创建一个configmap用于保存应用程序用到的字段值

apiVersion: v1
kind: ConfigMap
metadata:
  name: myconfig
  namespace: default
data:
  special.level: info
  special.type: hello

变量注入方式在Pod中使用configmap:

apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: busybox
      image: busybox
      command: [ "/bin/sh", "-c", "echo $(LEVEL) $(TYPE)" ]
      env:
        - name: LEVEL
          valueFrom:
            configMapKeyRef:
              name: myconfig
              key: special.level
        - name: TYPE
          valueFrom:
            configMapKeyRef:
              name: myconfig
              key: special.type
  restartPolicy: Never

查看Pod日志就可以看到容器里打印的键值了:

# kubectl logs mypod 
info hello

举一个常见的用法,例如将应用程序的配置文件保存到configmap中,这里以redis为例:

apiVersion: v1
kind: ConfigMap
metadata:
  name: redis-config
data:
  redis.properties: |
    redis.host=127.0.0.1
    redis.port=6379
    redis.password=123456
---
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: busybox
      image: busybox
      command: [ "/bin/sh","-c","cat /etc/config/redis.properties" ]
      volumeMounts:
      - name: config-volume
        mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: redis-config
  restartPolicy: Never

查看Pod日志就可以看到容器里打印的文件了:

# kubectl logs mypod 
redis.host=127.0.0.1
redis.port=6379
redis.password=123456

10.3 应用程序如何动态更新配置?

ConfigMap更新时,业务也随之更新的方案:

  • 当ConfigMap发生变更时,应用程序动态加载

  • 触发滚动更新,即重启服务

  • sidecar 模式监听配置文件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值