kubernetes整理知识点

基本介绍:

编排历史:

服务编排系统 =》容器编排系统
docker compose\swarm\docker machine
mesos,marathon
kubernets

集群节点:

聚合了所有node的cpu和内存,能自动寻找适合的node

运行单元:

pods

master组成:

APIserver接收请求放到etcd,其他如kubectl、scheduler、controller与apiserver打交道
scheduler调度,给一个pod找一个node
controller负责监控执行,有个循环loop 
etcd(保存整个集群的配置,key-value),服务端口(其他证书)和集群内通信端口(点到点证书)

node组成:

kubelet负责和master连接,注册node, listen-watch 本node的任务等
kube-proxy用于k8s service对象,监控service的变动,变为当前node的iptables
container runtime除了docker k8s还支持 rkt等容器实现

Addons附件:

DNS(kube-dns ==> coredns)主要用来解析service域名
CNI网络容器接口(如fannel calico),pod,网络是节点网络类型,提供网络策略通过名称空间来隔离租户
    flannel网络配置,叠加网络,不支持网络策略
    calico网络配置、网络策略,三层隧道网络
    canel:结合两者
    weave网络策略
web ui
container resource monitoring
cluster-level logging

证书:

5套证书,分内部和外部服务通信

常用对象:

Workload:

分为Pod ReplicaSet Deployment statefulSet DaemonSet Job CronJob
pods,k8s管理的最小对象,是一组共享uts, network, ipc namespace的容器(也支持共享pid,默认不开启)
rc和rs等controller(管理pods)
deployment
    简单地说deployment是rc的上一层,用来管理rc的
    主要功能是管理pod运行的版本

服务发现与均衡:

service
    pod是非持久的,会不断的重启,导致pod的ip是随时变化的,同时pod的数量会是动态变化的,客户端很难和pod直接通讯,service是用来解决这一问题的
    service 为提供同一服务的pods 提供了统一的入口
    service 的生命周期内其绑定ip是不会变化的
    通过环境变量或者DNS 可以查询service 的ip和端口
    之前创建的service只有一个集群内的固定ip,如果需要在集群外访问有三种方法
        默认的service 的类型是 'ClusterIP',修改为NodePort即可
        创建一个loadbalance
        创建Ingress resource
Ingress

配置与存储:

Volume

集群级资源:

namespace,node,role,clusterRole,RoleBinding

部署与安装:

部署要点:

测试环境:

可以使用单master节点,单etcd实例
node数量按需
nfs或glusterfs等存储

生产环境:

高可用etcd集群,建立3/5/7
高可用master
    -kube-apiserver无状态,可多实例,借助nginx\happorxy负载
    kube-scheduler及kube-controller-manager各自只能有一个活动实例,可以选举备用
多node
IScsi、fcsan

网络(本地多vm):

节点网络:172.20.0.0/16
pod网络:10.244.0.0/16 fannel默认使用
service网络:10.96.0.0/12

常用部署工具:

kubeadm
kops
kubespray
kontena pharos

集群架构组成:

初始化:

所有节点启动docker
初始化master(运行三个controller、etcd)和node(kube-proxy)

基础组件:

master和node启动kubelet和CNI

kubeadm部署流程:

1.更新下载源

配置yum或apt阿里云源,yum下载gpg,定义.repo文件
    https://developer.aliyun.com/mirror/kubernetes
    ubuntu下:
        sudo apt-get update && sudo apt-get install -y apt-transport-https
        curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add - 
        cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
        deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
        EOF
        k8s_version="1.18.0-00"
        apt-get update
        apt-get install -y kubelet=${k8s_version} kubeadm=${k8s_version} kubectl=${k8s_version}

2.安装软件

install docker-ce kubelet kubeadm=v1.11.0 kubectl,并且enable docker-ce kubelet

3.docker拉取所需镜像

通过代理拉取:
路径是/etc/systemd/system/docker.service.d/http-proxy.conf或/usr/lib/systemd/system/docker.service
Environment="HTTPS_PROXY=http://www.ik8s.io:10080"
Environment="NO_PROXY=127.0.0.0/8,172.20.0.0/16"
systemctl daemon-reload
systemctl start docker
通过tag重命名的方式:
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-apiserver:v1.18.1
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-controller-manager:v1.18.1
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-scheduler:v1.18.1
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/kube-proxy:v1.18.1
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.2
docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.4.3-0
docker pull coredns/coredns:1.6.7
docker images |grep registry.cn-hangzhou.aliyuncs.com/google_containers |awk '{print "docker tag ",$1":"$2,$1":"$2}' |sed -e 's#registry.cn-hangzhou.aliyuncs.com/google_containers#k8s.gcr.io#2' |sh -x
docker tag docker.io/coredns/coredns:1.6.7 k8s.gcr.io/coredns:1.6.7
docker images |grep mirrorgooglecontainers |awk '{print "docker rmi "$1":"$2}' |sh -x

4.初始化部署

swapoff -a
kubeadm reset -f && rm -rf /etc/kubernetes/
kubeadm init --kubernetes-version=v1.11.0 --pod-network-cidr=10.244.0.0/16 --service-cidr=10.96.0.0/12 初始化
    --ignore-preflight-errors=SystemVerification --ignore-preflight-errors=KubeletVersion
    --control-plane-endpoint=apulis-china-infra01.sigsus.cn
    --image-repository=harbor.sigsus.cn:8443/library/k8s.gcr.io
执行后续提示步骤
出错原因查看:journalctl -xeu kubelet
    如果还不是很明确,可以继续通过docker ps -a和docker logs xxx查看容器具体的报错的信息

    标准的初始化流程可以参考官方文档https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/

配置kubectl的文件
    mkdir -p $HOME/.kube
    sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
    sudo chown $(id -u):$(id -g) $HOME/.kube/config

5.部署其他组件:

CNI:
部署flannel:
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=v1.18.1"
sudo scp dlwsadmin@apulis-sz-sanbox-master:/etc/kubernetes/admin.conf ./deploy/sshkey/admin.conf
部署weave:
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')&env.IPALLOC_RANGE=10.32.0.0/16"
DNS(coredns):
https://github.com/kubernetes/kubernetes/blob/e176e477195f92919724bd02f81e2b18d4477af7/cluster/addons/dns/coredns/coredns.yaml.sed
修改clusterIP为10.3.0.53,删除配置中的loop
效果:
    部署完后,集群内pod之间、service与pod之间就可以访问域名通信。
    service的更新实时通过kube-proxy获取api-server来更新dns的service地址到本地
    删除dns后又重新添加,dns的service网络地址不变
问题:
    1.部署机可以访问pod网络,但因为resolv.conf不变,不能访问service域名
    2.无法解析集群外域名
        解决:修改resolv.conf,但unable to resolve host,因为本地host依赖本地的dns,编辑/etc/hosts,把主机名加到127.0.0.1即可。
        或者启动coredns时,指定forward . 8.8.8.8

6.worker节点部署:

安装docker
使用kubeadm join的方式初始化子节点:
    token可以通过kubeadm token create和openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
    组合成kubeadm join --token %s %s:6443 --discovery-token-ca-cert-hash sha256:%s
        kubeadm token create --ttl 0 --print-join-command
多次部署:
    systemctl stop kube-proxy
    systemctl stop kubelet
    systemctl stop docker
    iptables --flush                # 修复no route to host
    iptables -tnat --flush
    iptables -P INPUT ACCEPT        # 设置filter表INPUT默认规则是 ACCEPT
    iptables -P FORWARD ACCEPT
    iptables -P OUTPUT ACCEPT
    iptables -F                 # 清空所有规则 
    systemctl start kubelet                 
    systemctl start docker

运维操作:

删除节点:

kubectl drain k8snode02 --delete-local-data --force --ignore-daemonsets node/k8snode02
kubectl delete node k8snode02
kubeadm reset(systemctl stop kubelet && rm -rf /etc/kubernetes/*)

master的ip变更:

kubeadm部署的:
1.重新生成证书,可以通过kubeadm alpha phase certs
2.把config文件、kubebconfig文件、/etc/kubernetes/文件夹里的*.conf文件的旧ip都改为新的IP
3.重启服务
二进制部署:
只要签发的证书没有指定master的ip,那么是不用重新生成证书的
只要把conf文件都改掉旧的ip即可
注意事项:
admin.confkubelet.conf以及crt文件里面都需要改动ip
方法:
systemctl stop kubelet docker
cd /etc/
mv kubernetes kubernetes-backup
mv /var/lib/kubelet /var/lib/kubelet-backup
mkdir -p kubernetes
cp -r kubernetes-backup/pki kubernetes

rm kubernetes/pki/{apiserver.*,etcd/peer.*}
systemctl start docker

# reinit master with data in etcd
# add --kubernetes-version, --pod-network-cidr and --token options if needed
# 原文使用如下命令:
# kubeadm init --ignore-preflight-errors=DirAvailable--var-lib-etcd
# 但是由于我使用的是Flannel网络,所以一定要加上参数,否则后续安装 flannel addon无法启动pod
# kubeadm init --ignore-preflight-errors=DirAvailable--var-lib-etcd --pod-network-cidr=10.244.0.0/16
kubeadm init --ignore-preflight-errors=all --kubernetes-version=v1.18.2

# update kubectl config
cp kubernetes/admin.conf ~/.kube/config

常见问题点:

初始化:

1.10250这个端口一直被/snap/kubelet/1388/kubelet的挂载目录给占用了。
    umount -fl即可
    如果强制卸载后,还是ps -ef|grep kube还是存在,可以rm /dev/loop0试试
2.子节点join失败。
    查看具体原因log -v 256
3.日志提示Error response from daemon: readlink /var/lib/docker/overlay2/l: invalid argument
    删除该目录会报错,link来的,然后重新拉取镜像就没问题了
4.worker节点reset后提示没有/etc/kubernetes/bootstrap-kubelet.conf
    systemctl status kubelet查看配置文件
    复制其他worker节点的文件过来,kubelet即可运行
5.提示error while creating mount source path '/var/lib/kubelet/pods/etc-hosts': mkdir /var/lib/kubelet: read-only file system
    重启docker
6.kubeadm init初始化失败,报node "ubuntu" not found
    原因: 
        通过docker logs查看pod启动失败原因,发现是k8s集群镜像的架构不同导致的,树莓派上的镜像之前已经自带的,导致apiserver启动失败。
7.Failed to create pod sandbox: open /run/systemd/resolve/resolv.conf: no such file or directory
    解决: 
        ln -s /run/resolvconf/ /run/systemd/resolve
8.kubelet提示panic: runtime error: invalid memory address or nil pointer dereference,不断重启
    原因:calico镜像有问题,delete掉deployment后,还残留了容器,docker ps -a查看,一直拉取旧的镜像。前一行提示了error image not found while inspecting docker container
9.init失败:
    # /etc/kubernetes/work-kubernetes.yaml需要配置,读取/etc/kubernetes/ssl/里面的相关证书  
    # 这是join用到的kubelet配置,会影响主节点的部署/etc/systemd/system/kubelet.service.d/10-kubeadm.conf
    # 后来发现是之前部署的10-kubeadm.conf遗留造成的影响,换为一个能用的就行
    # 没有10-kubeadm.conf会一直空跑

网络CNI:

1.weave端口被占用也会导致容器网络失败,通过lsof -i:xxx 查看,然后kill -9 pid即可重启weave,但有可能open /weavedb/weave-netdata.db失败,delete pod然后再启动一次即可。
2.新节点加入weave报错Could not get peers: Get https://10.96.0.1:443/api/v1/nodes: dial tcp 10.96.0.1:443connectno route to host
    kube-proxy还没启动,导致无法路由
3.提示[192.168.3.2:6783|be:87:40:f0:e9:c2(atlas01-worker01)]: connection shutting down due to error: IP allocation was seeded by different peers (received: [ca:1c:e7:11:2c:9f],ours: [02:61:5f:88:9a:d9(atlas01)])
    关联问题:On a network with multiple interfaces weave uses different ones on different hosts
    解决方案:
        some Weave Net peers were initialized into one cluster and some into another cluster; Weave Net cannot operate in this state.
        https://www.weave.works/docs/net/latest/tasks/ipam/troubleshooting-ipam/#seeded-different-peers
        https://github.com/weaveworks/weave/issues/3588
        rm -rf /var/lib/weave
        重启weave
4.FATA: 2020/09/17 14:57:45.957005 [kube-peers] Could not get peers: Get "https://10.96.0.1:443/api/v1/nodes": dial tcp 10.96.0.1:443: i/o timeout
    Failed to get peers
    查看kube-proxy的log: 
        10.96.0.1 in clusterIP has incorrect IP version (service default/kubernetes)
    解决: 
        看kubelet status可以看到NetworkPluginNotReady message:docker: network plugin is not ready: cni config uninitialized,weave引起的
        主要解决weave即可
        curl -vk https://10.96.0.1

        怀疑和机器本身的网卡驱动有关

        x86也遇到过,禁用ipv6后成功启动weave
            sysctl net.ipv6.conf.all.disable_ipv6=1

            vim /etc/sysctl.d/10-disable-ipv6.conf
            write_files:
              - path: /etc/sysctl.d/10-disable-ipv6conf
                permissions: 0644
                owner: root
                content: |
                  net.ipv6.conf.eth0.disable_ipv6 = 1

        后来发现是机器本身的内核问题,换一台机器就好了,但不是根治之法

        默认要有一个default router

        查阅了一下,手动添加route: 
            ip route add 10.96.0.0/12 dev eno1 src 10.31.3.63 无效

        可能与iptables-save规则有关
            iptables -A KUBE-SERVICES -d 10.96.0.1/32 -p tcp -m comment --comment "default/kubernetes:https cluster IP" -m tcp --dport 443
            或者直接reset整个iptables                     

            验证:
                iptables -A KUBE-SERVICES -d 10.96.0.1/32 -p tcp -m comment --comment "default/kubernetes:https cluster IP" -m tcp --dport 443 -j REJECT
                删掉weave pod后果然起不来

        还是无效的话,重启reboot看看

    发现与coredns解析连不了8.8.8.8有关,因为看到了域名解析错误,将机器连上网后正常。
    一般不用管iptables
5.kubernetes ha vip起来,但其他组件无法访问vip,查看VIP的log发现ipv6达不到
    手动添加对应的inet6无效
    swapoff -a
    sed -i 's/.*swap.*/#&/' /etc/fstab
    setenforce 0
    echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables
    echo 1 > /proc/sys/net/bridge/bridge-nf-call-ip6tables
    echo 1 > /proc/sys/net/ipv4/ip_forward
    echo 1 > /proc/sys/net/ipv6/conf/default/forwarding
    sysctl -w net.bridge.bridge-nf-call-iptables=1
    vim /etc/sysctl.conf
        net.ipv4.ip_forward=1
        net.bridge.bridge-nf-call-iptables=1
        net.bridge.bridge-nf-call-ip6tables=1
    sysctl -p
    重启电脑后才生效

6.weave组件Inconsistent bridge state detected. Please do 'weave reset' and try again
    下载weave脚本,执行weave reset,会短暂断网
    https://github.com/weaveworks/weave/blob/master/weave
    wget https://raw.githubusercontent.com/weaveworks/weave/master/weave
7.weave组件启动异常,提示Network 10.32.0.0/12 overlaps with existing route 0.0.0.0/1 on host
    确认是否启动了全局代理vpn,先移除再启动
8.weave组件启动后,interface的ip和在controller中cluster ip设置的范围不一样,造成了pod内无法通信
    yaml文件里面定义:
        containers:
        - name: weave
          env:
            - name: IPALLOC_RANGE
              value10.0.0.0/16
    先停止,删掉interface,再reset,然后启动即可。
9.weave报错的情况下,pod还能分配到node上,拥有host???
    问题:
        发现master无法部署,即使去掉taints,后来发现dns无法nodenotready,原来是weave启动失败,
        更换flannel后,同时edit master的pod_cidr为相同的network,就可以启动。

运维:

1.遇到pod rpc deallock等error,一直pengind、terminating中
重新加入worker节点
2.pod一直处于Terminating,docker ps查看进程存在,stop kill rm -f都不成功
原因:/var/lib/docker/containers/文件存在,可能是container清理时网络问题导致文件未清理掉,造成进程已退,但文件存在的假container
    npu的脚本报错会导致kill不掉,原因是sudo -E bash -c cd /data/code/mindspore/example/resnet50_cifar10/ && ./run_8p.sh &&sleep infinity的./run_8p.sh报错了
    如果正常执行,则不会出现该情况
解决: 
    删除/var/lib/docker/containers/下的对应文件夹
    systemctl restart docker
    或kubectl delete pod --force  xxx  但docker没清掉
    或docker top xxx查看容器停留进程,然后kill 进程号试试
重现:
    再次跑job后,仍然出现该情况
3.pod的port通过service转发,pod内进程是启动的,内网ip+targetport可以访问,但通过service的cluster_ip+port或外网ip+nodeport不能访问
iptables-save |grep 10.104.74.188
-A KUBE-SERVICES -d 10.104.74.188/32 -p tcp -m comment --comment "default/e-461e6f51-66fc-4969-8eec-65ec74960c91-ipython:ipython has no endpoints" -m tcp 
    --dport 44460 -j REJECT --reject-with icmp-port-unreachable
意思是44460端口不可访问
    网上搜索说selector错误,但pod是启动的
4.pod内Unable to connect to the server: dial tcp 10.96.0.1:443: i/o timeout,kubectl或python接口都超时
原因: ufw启动,本地访问6443端口是可以的,但容器内不能访问。容器内网络是正常的。
解决: ufw allow 6443
5.树莓派出现[ERROR SystemVerification]: missing cgroups: memory
解决:
/boot/firmware/cmdline.txt和/boot/firmware/nobtcmd.txt添加cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1
6.pod一直处于containcreating状态。kubernetes Get https://[10.96.0.1]:443/apis/crd.projectcalico.org/v1/clusterinformations/default: x509: certificate signed by unknown authority
/etc/cni/net.d/目录下面有其他的网络插件,比如calio,删除掉
ip route flush proto bird
ip link list | grep cali
iptables-save|grep cali 
modprobe -r ipip
service kubelet restart 
7.pod状态出现diskpresure
vi /var/lib/kubelet/config.yaml
evictionHard:
  nodefs.available: "5%"
8.pod内resolf.conf文件没有nameserver
过程:
该节点卸载过avahi,该软件导致了默认route的改变,增加了网卡,卸载导致systemd-resolved.service起不来。
解决:
重启,然后服务正常,但nslookup查找失败
ls -l /etc/resolv.conf可以看到指向不正常
rm /etc/resolv.conf
ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf正常的软链才是正常的,pod内使用的/etc/resolv.conf文件也是这个,systemd-resolved 实时更新 /run/systemd/resolve/stub-resolv.conf
9.容器内其他用户执行kubectl提示error: You must be logged in to the server (Unauthorized)
原因:
每个pod都挂载了default token,对应serviceaccount的default,该token由TokenController 作为 kube-controller-manager 的一部分运行。
使用了该default token导致kubectl返回401错误(kubenretes的python api也会401
    from kubernetes import client as k8s_client
    from kubernetes import config as k8s_config
    k8s_config.load_incluster_config()
    k8s_core_api = k8s_client.CoreV1Api()
    k8s_core_api.list_namespaced_config_map(namespace="default")
该token可以通过jwt解,但只是一些基本信息。看kubelet的报错,原因可能是挂载的token是旧的,对应的已经被删除了。
解决:
删掉token,等待自动生成。
9.pod一直处于pulling,同时有多个pod
原因:kubelet默认串行拉取镜像,改为并行
查找:kubelet -v可以设置更高的级别,输出更多的log

DNS:

1.coredns问题
查看本地dns服务是否启动,排除weave是否正常,ping内网ip是否通,
查看coredns的pod,依赖配置configmap:coredns,kgk cm coredns -o yaml查看配置
查看coredns的log,发现dial udp [fdcd:55c4:4289::1]:53connect: cannot assign requested address
    通过netcat工具,nc -z -v -u [hostname/IP address] [port number]
    原因:fdcd:55c4:4289::1是根据configmap中的forward . /etc/resolv.conf来导向的,看看/etc/resolv.conf是否有问题
一直CrashLoopBackOff
    [FATAL] plugin/loop: Loop (127.0.0.1:37845 -> :53) detected for zone ".", see https://coredns.io/plugins/loop#troubleshooting. Query: "HINFO 5239076309015988897.2370766897435033976."
    原因: loop 
        修改本地127.0.0.538.8.8.8

常用指令:

kubectl get nodes
            pods -n kube-system -o wide\yaml\json
            ns
            svc
        run nginx-dep --image=nginx:1.14-alpine --port=80 --replicas=1  # 启动的是deployment,如果想运行pod的话,kubectl run nginx --image=nginx --port=80 --restart=Never
        expose deployment nginx-dep --name=xxx --port=80 --target-port=80 --protocol=TCP --type=ClusterIP
            创建service来动态绑定端口,nodePort类型才能被外网访问
        edit svc xx
        scale deployment xx --replicas=5
        set image deployment myapp myapp=ikuberbetes/myapp:v2
        rollout status deployment myapp灰度更新
                history\undo\pause\resume
        patch deployment myapp -p '{"spec":{"replicas":5}}'
        create ns(namespace) xxx
                deploy ngx --image=nginx:1.14-alpine # 自动重启,ip会变(集群内才能访问该ip),加service层
                    会启动pod
                service clusterip my-cs --tcp=5378:8000 # 与deploy同名会自动关联过来
                service nodeport my-ns --tcp=       # 区别是外网可以访问,但不是指定端口
        delete ns/xxx ns/yyy 可以一次输入多个
        api-resources
        describe
        exec -it xxx /bin/bash
            pod-demo -c 某个container -n prod -it -- /bin/bash
        scale --replicas=3 deployment mydeploy扩容后svc自动添加负载
        log pod xxx -n prod -c container
        cluster-info

概念介绍:

Controller种类:

概述:

Kubernetes 通常不会直接创建 Pod,而是通过 Controller 来管理 Pod 的。

分类:

ReplicationController(旧)
ReplicaSet:指定数量的副本,不建议直接使用,而是使用deployment ;扩缩容可以scale或edit;
        升级edit不会更新已存在的pod,只能蓝绿更新
Deployment:通过控制ReplicaSet来控制pod,功能大于replicas,支持灰度滚动更新(管理多个rs来实现)
        配置更新可以编辑文件然后apply\set image\patch
DaemonSet:每个节点运行,node守护进程,适合node节点收集路径日志的服务,由k8s维护重启
StatefulSet:状态,如redis,持久存储
Job:执行一次
Ctonjob:周期执行
HPA

网络:

节点网络:

与外部网络接口,运维提供,而其他两种网络由插件通过

service网络:

概述:
内部网络,无法外部访问,通过coreDns注册;被删前稳定ip
实现原理:
不是实体组件,而是一套iptable规则,其service名称通过自身的dns来解析
请求通过service访问pod,而iptable将负载交给ipvs提供负载平衡功能,即相当于生成了ipvs规则
当pod状态变更时,service通过守护进程kube-proxy改变节点的相关ipvs规则

pod网络:

概述:
由cni提供,一般加一层service网络代理,service通过label与pod绑定
实现原理:
pod之间可以通过overlay network叠加网络相互访问,而service只是规则
(如果直接物理桥桥接,pod数量多了不够分,通过叠加网络二层转发或隧道转发三层)
访问过程:
docker之间先转发出节点,再相互通信
pod要访问service,先请求网关,到达临桥地址通过iptabel规则表找到service

service资源:

工作原理:

pod之间请求通过service,pod的更新到apiserver后,apiserver通过kube-proxy通知service进行更新

工作模式:

userspace、iptable、ipvs

type类型:

ExternalName, ClusterIP, NodePort,LoadBalancer,Headless.
NodePort
    会将对本地集群任何一个机器ip的某一个port的请求转发到相应的cluster ip+port上
    Port的范围是所有机器共享的
Headless
    无头service,clusterIP: None #None表示是无头service
    会直接解析为具体多个pod的ip
    该服务不会分配Cluster IP,也不通过kube-proxy做反向代理和负载均衡。而是通过DNS提供稳定网络ID来访问,DNS会将headless service的后端直接解析为podIP列表。主要供StatefulSet使用。
LoadBalancer:
    和nodePort类似,不过除了使用一个Cluster IP和nodePort之外,还会向所使用的公有云申请一个负载均衡器(负载均衡器后端映射到各节点的nodePort),实现从集群外通过LB访问服务。
    云平台底层将请求负载转发给各个nodePort的service,service再分发给pod
ExternalName:
    集群内的pod访问外部服务,私网ip回不来
    建一个service,由service请求外部服务,请求先回到service,再转发给pod
    是 Service 的特例。此模式主要面向运行在集群外部的服务,通过它可以将外部服务映射进k8s集群,且具备k8s内服务的一些特征(如具备namespace等属性),来为集群内部提供服务。

访问url格式:

svc_name.ns_name.domain.ltd
例如redis.default.svc.cluster.local.

配置示例:

apiVersion:v1
kind: Service
metadata:
    name:
    namespace
spec:
    selector:
        app:nginx
    clusterIP:          # 分配
    type: ClusterIP     # nodePort 会在宿主机上映射一个端口,供外部应用访问模式。
    ports:
    - port:6379             # service映射端口
      targetPort: 6379      # 容器内端口
      nodePort: 33080       # 指定node的端口,默认30000-32767

Ingress:

作用:

外部https请求到达nginx,nginx通过url前缀转发给不同的services,再由service转发给对应一组pod

部署方案:

方法一:将nginx部署为daemonset,部分节点,nginx内配置多个location,location代理给services。
        再为多个nginx部署一个nodeport的service,指定nodePort,就可以接入外部请求
方法二:Ingress controller资源,先部署一个nginx的deployment,再部署一个ingress,路由多个path

安装:

1.创建namespace\configmap\rbac\tcp-services-configmap\with-rbac yaml文件
2.kubectl apply -f ./部署nginx
3.定义ingress
apiVersion:extensions/v1beta1
kind:Ingress
metadata:
    name:ingress
    namespace
    annotations:
        kubernetes.io//ingress.class:"nginx"
spec:
    tls:
    - hosts:
      - tomcat.com
      secretName:tomcat-ingress-secret
    rules:
    -host:myapp.com
     http:
        paths:
        - path:     #空为根路径
          backend:
            serviceName:myapp
            servicePort:80      # service端口,而ingress的nginx端口默认为80和443,现在不能更改
4.定义后nginx自动更新配置
#pod更新后,nginx的upstream也会自动更新
5.https,先openssl生成证书和密钥,然后创建secret对象
openssl genrsa -out tls.key 2048
openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Beijing/L=Beijing/0=DevOps/CN=tomcat.com
kubectl create secret tls tomcat-secret --cert=tls.crt --key=tls.key

kube-ApiServer:

restful api server,上面的指令实际都是http请求的不同action,get\put\post
资源对应着url

资源对象的配置格式:

kind:用于标识对象所属的资源类型、api群组
apiVersion
metadata:名称、namespace、标签
spec:包括一些container,storage,volume以及其他Kubernetes需要的参数,以及诸如是否在容器失败时重新启动容器的属性。
status:

资源对象管理方式:

创建:

陈述式命令     run
陈述式对象配置    create -f
声明式对象配置    apply,用于添加,删除使用陈述式对象配置的delete,配置文件修改了可以再次apply。可以目录

区别:

run创建deploymnet,pod由控制器管理,而后两种只是创建pod

Pod:

pod对象创建过程:

1.提交create pod
2.apiserver写入etcd,etcd成功后响应
3.apiserver调度scheduler,watch new pod
4.scheduler bind pod给apiserver
5.apiserver写入etcd
6.apiserver请求kubelet,watch bound pod
7.kubelet请求docker run
8.kubelet update pod status给apiserver
9.apiserver写入etcd

pod的终止过程:

1.提交delete请求,apiserver标记为terminating
2.apiserver写入etcd,设置grace period
3.apiserver请求kubelet,watch pod marked as terminating
4.kubelet send term signal给docker
5.kubelet run preStop hook
6.apiserver请求endpoint controller,remove pod from endpoint of all service
7.apiserver watch expiry of grace period,请求kubelet,kubelet send SIGKILL给docker
8.docker 立刻删除pod
9.apiserver 请求删除etcd对应的object

pod生命周期:

状态:
Pending         API Server已经创建该Pod,但在Pod内还有一个或多个容器的镜像没有创建,包括正在下载镜像的过程。
Runnung         Pod内所有容器均已创建,且至少有一个容器处于运行状态、正在启动状态或正在重启状态。
Succeeded       Pod内所有容器均成功执行后退出,且不会再重启。
Failed          Pod内所有容器均已退出,但至少有一个容器退出为失败状态。
Unknown         由于某种原因无法获取该Pod的状态,可能由于网络通信不畅导致
相关钩子:
postStart:
httpGet\exec\tcpSocket
容器启动后立刻执行,如果执行失败会根据policy重启与否
preStop:
存活探测:
livenessProbe健康监测:  位于containers层面
    exec:(0表示成功)
        command
    httpGet(返回200状态码)
        host
        port:必须,name或数字
        path:
    tcpSocket
        host
        port
    failureThreshold
    initialDelaySeconds
    periodSeconds
    timeoutSeconds
就绪探测:
readinessProbe:
无论就绪ready与否,不能重启,只是不能作为服务被引用
ready后才被server引用会更合理,比如多个replicas的一个,还没就绪会导致502

重启策略:

always:但凡对象终止就重启
onfailure
never

pod security:

级别:
pod.spec.securityContext
pod.spec.container.securityContext
    capabilities add/drop

资源设置:

cpu一个核心=1000m
pods.spec.containers.resources
    limits最高限制
    requests申请资源

pod服务质量:

Guaranteed:为cpu和内存设置了相同request和limit的pod会自动归属此类,最高优先级
Burstable:至少一个容器设置了cpu和内存资源的request
BestEffort:未设置requests或limit属性,最低优先级

其他知识点:

priorityClass
limitRange

关于Command和args:

如果定义了args,会使用docker镜像的entrypoint,忽略cmd

关于yaml格式的书写:

[]string这种,可以使用["/usr/sbin/nginx","-s","quit"]来表示,也可以- -

多个容器:

边车,side car
一个主容器,其他容器辅助,如日志收集、后台服务的proxy代理
共享IPC、UTS、network、volumes

yaml文件示例:

apiVersion: v1       #必选,版本号,例如v1
kind: Pod       #必选,Pod
metadata:       #必选,元数据
  name: string       #必选,Pod名称
  namespace: string    #必选,Pod所属的命名空间
  labels:      #自定义标签
    - name: string     #自定义标签名字
  annotations:       #自定义注释列表
    - name: string
spec:         #必选,Pod中容器的详细定义
  containers:      #必选,Pod中容器列表
  - name: string     #必选,容器名称
    image: string    #必选,容器的镜像名称
    imagePullPolicy: [Always | Never | IfNotPresent] #获取镜像的策略 Alawys表示下载镜像 IfnotPresent表示优先使用本地镜像,否则下载镜像,Nerver表示仅使用本地镜像
    command: [string]    #容器的启动命令列表,如不指定,使用打包时使用的启动命令
    args: [string]     #容器的启动命令参数列表
    workingDir: string     #容器的工作目录
    volumeMounts:    #挂载到容器内部的存储卷配置
    - name: string     #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
      mountPath: string    #存储卷在容器内mount的绝对路径,应少于512字符
      readOnly: boolean    #是否为只读模式
    ports:       #需要暴露的端口库号列表
    - name: string     #端口号名称
      containerPort: int   #容器需要监听的端口号
      hostPort: int    #容器所在主机需要监听的端口号,默认与Container相同,
      protocol: string     #端口协议,支持TCP和UDP,默认TCP
    env:       #容器运行前需设置的环境变量列表
    - name: string     #环境变量名称
      value: string    #环境变量的值
    resources:       #资源限制和请求的设置
      limits:      #资源限制的设置
        cpu: string    #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
        memory: string     #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
      requests:      #资源请求的设置
        cpu: string    #Cpu请求,容器启动的初始可用数量
        memory: string     #内存清楚,容器启动的初始可用数量
    livenessProbe:     #对Pod内个容器健康检查的设置,当探测无响应几次后将自动重启该容器,检查方法有exec、httpGet和tcpSocket,对一个容器只需设置其中一种方法即可
      exec:      #对Pod容器内检查方式设置为exec方式
        command: [string]  #exec方式需要制定的命令或脚本
      httpGet:       #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
        path: string
        port: number
        host: string
        scheme: string
        HttpHeaders:
        - name: string
          value: string
      tcpSocket:     #对Pod内个容器健康检查方式设置为tcpSocket方式
         port: number
       initialDelaySeconds: 0  #容器启动完成后首次探测的时间,单位为秒
       timeoutSeconds: 0   #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
       periodSeconds: 0    #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
       successThreshold: 0
       failureThreshold: 0
       securityContext:
         privileged:false
    restartPolicy: [Always | Never | OnFailure]#Pod的重启策略,Always表示一旦不管以何种方式终止运行,kubelet都将重启,OnFailure表示只有Pod以非0退出码退出才重启,Nerver表示不再重启该Pod
    nodeSelector: obeject  #设置NodeSelector表示将该Pod调度到包含这个label的node上,以key:value的格式指定
    imagePullSecrets:    #Pull镜像时使用的secret名称,以key:secretkey格式指定
    - name: string
    hostNetwork:false      #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
    volumes:       #在该pod上定义共享存储卷列表
    - name: string     #共享存储卷名称 (volumes类型有很多种)
      emptyDir: {}     #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
      hostPath: string     #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
        path: string     #Pod所在宿主机的目录,将被用于同期中mount的目录
      secret:      #类型为secret的存储卷,挂载集群与定义的secre对象到容器内部
        scretname: string  
        items:     
        - key: string
          path: string
      configMap:     #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
        name: string
        items:
        - key: string
          path: string

label:

标签就是键值
key:字母、数字、_、-、.
value:可以为空,只能字母或数字开头及结尾
一个对象可多个标签,一个标签可添加到多个资源上
key通常由键前缀和键名组成,前缀可选
使用:
    metadata定义后apply应用
    kubectl label --overwrite pod key=val key-删除
快速清空label:
    kubectl edit编辑删除

label selector:

基于等值关系
    = == !=
基于集合关系
    key in\not in ()
    key 所有存在此key的资源
    key
    !key
逻辑:
    多个选择权为“与”
    空值意味着每个资源对象都被选中
    空的选择器将无法选出任何资源
使用:
    kubectl get pods --show-labels -l app
=myapp
                    -l "app in (myapp,dep)" -L app 显示该标签 -l是选择
                    -l '!app'
控制器配置文件使用:
    matchLabels:直接给定键值
    matchExpressions:给定表达式,{key:"KEY",operator:"OPERATOR",values:[value1,value2..]}
        operator操作符:
            In,notIn:非空列表
            Exists,NotExists:必须空列表

资源注解annotation:

仅用于为资源提供元数据信息,不能用于挑选资源对象。没有长度限制
apply就用到这个来对比更新

更新策略:

重建:

概述:
会终止所有正在运行的实例,然后用较新的版本来重新创建它们。
示例:
spec:
  replicas: 3
strategy:
    type: Recreate

蓝绿发布:

概述:
同时运行两个版本的应用,如上图所示,蓝绿部署的时候,并不停止掉老版本,而是直接部署一套新版本,等新版本运行起来后,再将流量切换到新版本上。
缺点:
对硬件的要求就是日常所需的二倍
示例:
创建新旧两个deployment(两个label,app和version)和service(selector不同),在测试新版本满足要求后,替换 label selector 中的版本标签

滚动更新:

概述:
滚动更新通过逐个替换实例来逐步部署新版本的应用,直到所有实例都被替换完成为止。
示例:
spec:
  replicas: 3
strategy:
    type: RollingUpdate
rollingUpdate:
      maxSurge: 2        # 一次可以添加多少个Pod
      maxUnavailable: 1  # 滚动更新期间最大多少个Pod不可用

灰度发布:

概述:
也叫金丝雀发布,起源是,矿井工人发现,金丝雀对瓦斯气体很敏感,矿工会在下井之前,先放一只金丝雀到井中,如果金丝雀不叫了,就代表瓦斯浓度高。
流程:
先启动一个新版本应用,但是并不直接将流量切过来,而是测试人员对新版本进行线上测试,启动的这个新版本应用,就是我们的金丝雀。
如果没有问题,那么可以将少量的用户流量导入到新版本上,然后再对新版本做运行状态观察,收集各种运行时数据,如果此时对新旧版本做各种数据对比,就是所谓的A/B测试(A/B测试是效果测试)。
当确认新版本运行良好后,再逐步将更多的流量导入到新版本上,在此期间,还可以不断地调整新旧两个版本的运行的服务器副本数量,以使得新版本能够承受越来越大的流量压力。
直到将100%的流量都切换到新版本上,最后关闭剩下的老版本服务,完成灰度发布。
示例:
方式一:
具有相同 Pod 标签的 Deployment,通过数量来控制流量的比例。
方式二:
需要更精确的控制策略,建议使用服务网格(如 Istio),它们可以通过权重或 HTTP 头等更好地控制流量。

statefulset:

概述:

Pod发生re-schedule后仍然要保持之前的网络标识和持久化存储

特点:

1.部署、扩展、更新、删除都要有顺序。
2.每个pod都有自己存储,所以都用volumeClaimTemplates,为每个pod都生成一个自己的存储,保存自己的状态
3.pod名字始终是固定的
4.service没有ClusterIP,是headlessservice,所以无法负载均衡,返回的都是pod名,所以pod名字都必须固定,StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod副本创建了一个DNS域名:$(podname).(headless server name).namespace.svc.cluster.local

组件:

headless service、statefulset、volumeClaimTemplate

适合场景:

有状态的应用

扩缩容:

scale\set image

创建示例:

spec:
serviceName:
template:

spec:
containers:

- name:myapp
  volumeMounts:
volumeClaimTemplate:        # 类似pvc
- metadata:
name:myappdata
spec:
    accessModes:["readwriteOnce"]
    resources:
      request:
        storage:2Gi
updateStrategy:

type:
rollingUpdate:

partition:默认0,指定大于数字才进行更新。一般先指定较大,更新没问题后修改为0全部更新

ReplicaSet:

概述:

运行维护一组副本pod
建议使用 Deployment 而不是直接使用 ReplicaSet

创建示例:

apiVersion
kind
metadata
spec
    replicas:2
    selector:
        matchLabels:以标签来选择pod是否符和,如果其他label碰撞了,随机kill一个
            app:myapp
    template
        metadata:
            name
            labels:至少符合selector规则
        spec:
            containers:

Deployment:

概述:

ReplicaSet的更高级
pod之间没有顺序
所有pod共享存储
pod名字包含随机数字
service都有ClusterIP,可以负载均衡    

创建示例:

apiVersion
kind:Deployment
metadata
    name
    namespace
spec:
    replicas:
    selector:
        matchLabels:
            app:myapp
    template:
        metadata:
            labels:
        spec:
            containers:
            -
    strategy:
        type:   recreate删一个建一个 or rollingUpdate
        rollingUpdate:
            maxSurge:
            maxUnavailable:
    reversionHistoryLimit:10

DaemonSet:

概述:

DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。 当有节点加入集群时, 也会为他们新增一个 Pod 。
当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。

适合场景:

在每个节点上运行集群守护进程
在每个节点上运行日志收集守护进程
在每个节点上运行监控守护进程
创建示例
apiVersion
kind:DaemonSet
metadata
    name
    namespace
spec:
    selector:
        matchLabels:
            app:myapp
    template:
        metadata:
            labels:
        spec:
            containers:
            -
    updateStrategy:
        type:onDelete类似recreate or rollingUpdate
        rollingUpdate:
            maxUnavailable:只能少不能多
    reversionHistoryLimit

存储卷:

种类:

emptyDir临时路径、hostPath

底层存储:

传统存储:
SAN:iSCSI...
NAS:nfs,cifs
分布式存储:
glusterfs,rbd,cephfs
云存储:
EBS\Azure

emptyDir:

volumes:
- name:xxx
emptyDir:
    medium:""或Memory
sizeLimit:
然后在containers中volumeMounts
    mountPath:
    name:
    readOnly:
    subPath:子路径

gitRepo:

clone一份到emptydir中使用,更新不会同步

hostPath:

volumes:
- name:xxx
hostPath:
path:
type:默认空字符串,不执行检查挂载文件类型,DirectoryOrCreate\FileOrCreate\Socket\CharDevice\BlockDevice

共享存储:

使用服务器部署nfs:
安装nfs-utils        sudo apt-get install nfs-kernel-server
vim /etc/exports      /dev/share *(rw,fsid=1,sync,no_subtree_check,no_root_squash)        *表示不限制ip,fsid注意需不同
                                    rw,sync,no_root_squash,insecure
    sync    将数据同步写入内存缓冲区与磁盘中,效率低,但可以保证数据的一致性
    async   将数据先保存在内存缓冲区中,必要时才写入磁盘
systemctl start nfs        # ubuntu下是sudo service nfs-kernel-server restart\sudo systemctl start nfs-kernel-server
    # 如果nfs而不是nfs4,原因可能是配置有问题
        apt-get purge nfs-kernel-server
        重新安装apt-get install nfs-kernel-server
sudo showmount -e localhost
sudo exportfs -rv        #将配置文件中的目录全部重新export一次!无需重启服务。
sudo nfsstat            #查看NFS的运行状态
客户端测试连接:
    #查看网络端口,NFS默认是使用111端口。要确保端口已开,不建议通过外网访问,而是集群内相互通信,这样就不需要内网与外网之间的端口映射(即开放外网端口)
    sudo apt install nfs-common
    sudo showmount -e apulis-china-infra01.sigsus.cn
    sudo mount -t nfs4 apulis-china-infra01:/mnt/share /dlwsdata  # 会暂时覆盖原来的目录
    sudo mount -t nfs4 -o vers=4 -o mountvers=4 sandbox2-storage:/data/share /mntdlw
其他服务器进行挂载:
mount  -t nfs 192.168.255.1:/data/volumes /mnt
umount /mnt
volumes:
- name:xxx
nfs:
path:/data/volumes
server:store01.com

能够多个pod共享读写,不能填写相对路径
问题:
mount.nfs: access denied by server while mounting  # ip和掩码的问题,改为*就可以
同一个集群内
    一个机器访问另一个机器,访问域名时注意的是使用内网ip,如果填的是公网段才能访问,那么将会access denied,只能192.168.0.0/24
        表示32-24=828次方表示256个可用ip,即最后一位是主机部分,前面三位是网络部分
        27位的网掩码是: 255.255.255.224,表示
    这个时候公网ip的111端口可以不开
华为集群
    没有内网ip,直接通过外网ip通信,那么116.66.187.0/24,其他同一网段的机器可以访问,但本机的域名解析为127.0.0.1,不符合公网限制,所以access denied
    或者将/etc/hosts里面的映射去掉也可以
mount.nfs: requested NFS version or transport protocol is not supported
    确认已经开启了nfs server 
挂载卡住:
    配置nfs 
        RPCMOUNTDOPTS="--manage-gids -p 13025"
    重启
        systemctl restart nfs-kernel-server
    确认防火墙已经开放了端口1112049,和配置的port

persistentVolumeClaim:

创建pv:
定义了多个nfs后,即可创建,定义和volumes差不多
apiversion
kind: PersistentVolume
metadata:
    name:pv001
    # 没有namespace,属于集群资源,这点比较关键!!!
    labels:
        name:
spec:
    nfs:                                                            # 除了nfs外,还支持hostpath、cephfs等,k8s内置支持。
        path:
        server:
    accessModes:["ReadWriteOnce","ReadOnlyMany","ReadWritemany"]
    capacity:
        storage:2Gi                                                 # 这个大小貌似不影响,用的是整个目录,目前只有 capacity 这个label可作為 resource request 的依據,用于pvc的申请
    persistentVolumeReclaimPolicy: Retain (default) and Recycle.
    storageClassName: xxx                                           # 每个 PV 可以属于某个类(Class),通过将其 storageClassName 属性设置为某个 StorageClass 的名称来指定。 
                                        # 特定类的 PV 卷只能绑定到请求该类存储卷的 PVC 申领。 未设置 storageClassName 的 PV 卷没有类设定,只能绑定到那些没有指定特定 存储类的 PVC 申领。                                
    hostPath:
        path: 
创建pvc:
kind:PersistentVolumeClaim
metadata:
    name:pvc
    namespace:default #和pod同一个命名空间
spec:
    accessModes:[]
    resources:
        requests:
            storage:6Gi
    selector:
        matchLabels                         # 不加selector时,任意匹配满足容量的
    volumeMode: Filesystem                  # 挂载为pod内的目录,此外还有Block,挂载为原始块设备。
    volumeName: aiplatform-model-data-pv    # 指定pv,当前版本18.2不能绑定已经绑定过的pv(一对一),会一直pending。
    storageClassName: nfs                   # 对应pv的类型,可以是手动创建的pv,或者由storageClass动态创建的。

不同名称空间的pvc可以同名字,pv是集群级别的资源,同名字肯定只能一个
pv和pvc是one to one的关系
使用:
volumeMounts:                        #挂载容器中的目录到pvc nfs中的目录
- name: www
  mountPath: /usr/share/nginx/html
  subPath: nginxpvc-test
volumes:
- name: www
  persistentVolumeClaim:              #指定pvc
    claimName: pvc-nfs
    readOnly

storageClass:

动态创建nfs目录,创建pv来满足pvc的需求

configMap:

放置配置,明文,pod挂载路径即可,key-value字典来设置data的方式
创建configMap:
    kubectl create configmap myconfig --from-file=key1=/path/txt --from-literal=key1=config1        # key都放到data下
    apiversion
    kind
    metadata
    data:
    binaryData:
env使用:
    env:
    - name:Nginx_Port
      valueFrom:
        configMapKeyRef:
            name: nginx-cofig   # configmap名字为nginx-cofig
            key: nginx_port     # data下的key为Nginx_Port的数据
            optional:           # 是否configmap要事先定义
    更新后pod中不会自动更新
volume使用:
    volumeMounts:
      - name: config
        mountPath: "/config"        # key为文件名/config/key,value为内容
        readOnly: true
    volumes:
    - name: config
      configMap:
        name: nginx-config
        items:
         - key:    # 指定要挂载的key,如果不指定,则生成多个文件。
           path:   # 指定key生成的file名字,可以替代默认的名字key
    更新后短暂时间后同步到pod

secret:

加密的方式来存储
创建secret:
    类型: 
        三种,kubectl create secret docker-registry\generic\tls
        docker-registry
            docker-registry用于spec.imagePullSecrets,生成后指定name即可
        generic
            typeOpaque
        tls
    示例:
        kubectl create secret generic mysql-root-password --from-literal=password=MyP@ss.8*9
        kubectl create secret generic ssh-key-secret --from-file=ssh-privatekey=/path/to/.ssh/id_rsa --from-file=ssh-publickey=/path/to/.ssh/id_rsa.pub
        kubectl create secret docker-registry harborsecret --docker-server=harbor.demo.com.cn --docker-username='docker-admin' --docker-password='==pwd==' --docker-email='admin@demo.com'
使用:
    generic的使用类似configmap,可以在env或volume中使用。
    volumes:
      - name: foo
        secret:
          secretName: mysecret
          items:
          - key: username
            path: my-group/my-username
            mode077
    env:
      - name: SECRET_USERNAME
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: username

认证:

认证=》授权=》准入控制
认证支持token令牌和证书tls
授权支持node、abac、RBAC、webhook等
访问apiserver可以curl访问kubelet proxy,然后再转发
kubectl如何认证:
    kubeconfig
pod如何认证:
    默认的使用default-token-xxx,仅有权限访问自身的属性,要想访问其他pod,需手动创建
    serviceAccountName
restful api\verb\http action
subject针对user\group\serviceaccount
object针对resource\group
action:get,list,watch,patch,delete,deleteconllection
objectUrl:
    /apis/<GROUP>/<VERSION>/namespace/<NAMESPACE>/<KIND>/<object_id>/
    不同的action
    两者分别对应起来,组合不同的permission
    permission给不同的role

用户账号serviceAccount:

主要是pod的账号,用来指定pod的管理其他pod权限,如一些系统级的pod,flannel
pod生成时默认有一个default-token存储卷,通过get secret查看
生成serviceAccount:
    kubectl create serviceaccount mysa -o yaml  还没任何权限,可以包含image pull secrets(也可pod直接指定)
    创建后,生成mysa-token-xxx的secret
如何使用:
    spec:
        serviceAccount:     # 需先使用rolebinding或clusterrolebinding绑定到role或clusterrole上
                            # 只能使用对应名称空间下的

账号:

kubectl config view查看配置信息
生成证书密钥,用k8s的证书openssl签发,然后config创建用户
相关操作:kubectl config use-context/set-cluster/set-context
    (umask 077;openssl genrsa -out czl.key 2048) 生成私钥
    openssl req -new -key dashboard.key -out dashboard.csr -subj "/O=czl/CN=czl"  证书签属请求
    用系统ca签:openssl x509 -req -in dashboard.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out dashboard.crt -days 365
    创建账号kubectl config set-credentials czl --client-certificate=./mage.crt --client-key=./czl.key --embed-certs=true
    创建context:kubectl config set-context czl@kubernetes --cluster=kubernets --user=czl
    创建集群: kubectl config set-cluster --kubeconfig=/tmp/admin.conf --server="https://172.20.0.73:6443" --certificate-authority=/etc/kubernetes/pki/ca.crt --embed-certs=true
    创建secret:create secret generic xxx -n kube-system --from-file=xx.crt=./xxx.crt --from-file=./xxx.key
删除: 
    kubectl --kubeconfig=config-demo config unset users.<name>
    kubectl --kubeconfig=config-demo config unset clusters.<name>
    kubectl --kubeconfig=config-demo config unset contexts.<name>
问题: 
    1.提示需要输入密码:
        正常的config view输入应该如下:
            apiVersion: v1
            clusters:
            - cluster:
                certificate-authority-dataDATA+OMITTED
                server: https://192.168.1.184:6443
              name: DLWS
            contexts:
            - context:
                cluster: DLWS
                useradmin
              namecontext-DLWS-admin
            current-contextcontext-DLWS-admin
            kind: Config
            preferences: {}
            users:
            - nameadmin
              user:
                client-certificate-data: REDACTED
                client-key-data: REDACTED
        看看set-credentials的参数是否对齐
    2.kubeconfig文件生成后,如果需要更改user等,需要删掉文件后重新生成,set-context等命令不会覆盖

RBAC:(用于pod的属性serviceAccount)
kubeadm init搭建的集群默认是启用了rbac --authorization-mode=Node,RBAC

role:
    operations:
    objects
rolebinding
    位于一个名称空间下
    user account或service account
    role
    # 也可以绑定clusterRole,作为当前binding所在ns下的管理员!!!
    # 可以建立一个clusterrole,然后rolebing为各个namespace下的管理员
clusterRole\clusterrolebinding
    集群级别

创建role
    create role reader --verb=get,list --resources=pods
    kind:Role
    rules:
    - apiGroups:
      - ""              # 一般不需指定
      resources:
      - pods
      verbs:
      - get
      - list
创建rolebinding
    create rolebinding name --clusterrole=name|--role=name
    kind:RoleBinding
    metadata:
        name
        namespace
    roleRef:
      apiGroup:rbac.authorization.k8s.io
      kind:Role
      name:pods-reader
    subjects:
    - apiGroup:rbac.authorization.k8s.io
      kind:User     # 可以是group,例如kubernetes-admin就属于system:masters组
                    # openssl x509 -in ./apiserver-kubelet-client.crt -text -noout
                    # serviceAccount
      name:czl
创建clusterrole
    create clusterrole NAME --verb=get,list,watch --resource=pods -o yaml
    其他类似
创建clusterrolebinding
    create clusterrolebinding NAME --cluster-role=xxx --user=xxx
    kubectl create clusterrolebinding default-cluster-admin --clusterrole=cluster-admin --serviceaccount=default:default --dry-run -o yaml

为node添加role
    kubectl label node master02 kubernetes.io/role=master

dashboard:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta8/aio/deploy/recommended.yaml
更改为nodePort后即可访问
选择serviceaccount的令牌或kubeconfig让dashboard认证到k8s集群
生成专门证书:
    (umask 077;openssl genrsa -out dashboard.key 2048)
    openssl req -new -key dashboard.key -out dashboard.csr -subj "/O=czl/CN=domain"  证书签属请求
    用系统ca签:openssl x509 -req -in dashboard.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out dashboard.crt -days 365
    创建secret:create secret generic xxx -n kube-system --from-file=xx.crt=./xxx.crt --from-file=./xxx.key
创建serviceaccount
    create serviceaccount xxx -n kue-system
进行rolebinding
    create clusterrolebinding xxx --clusterrole=cluster-admin --serviceaccount=kube-system:dashboard-admin
找到绑定后生成的secret,describe打开复制令牌token即可
要想使用证书
    权限控制
        创建一个serviceaccount
        create rolebinding xxx --clusterrole=admin --serviceaccount=default:xxx
        config set-cluster kubernetes --certificate-authority=./ca.crt --server="https://172.20.0.0:6443" -embed-certs=true --kubeconfig=/tmp/admin.conf
    设置用户账号
        # 解密token: kubectl get secret xxx -o json这个其实就是describe获取到的base64加密后的,每个sa账号自动创建
        config set-credentials admin --token=xxxxxx --kubeconfig=/tmp/admin.conf
        kubectl config set-context xxx@kuberbetes --cluster=kubernetes --user=admin --kubeconfig=/tmp/admin.conf
        config use-context xxx@kuberbetes --kubeconfig=/tmp/admin.conf
    自定义证书如何生成配置:
        config set-credentials xxx --client-certificate=./xxx.crt --client-key=./xxx.key导入证书
        使用set-context设置所绑定的用户:set-context xxx --cluster=kuberbetes --user=xxx

CNI:

概述:

容器间通信
包含两个,一个是cni工具bin(coredns和kubelet都依赖),一个是cni插件,如weave

flannel:

背景:
container1要想与外界通信并且回来,本身生成的虚拟网卡eth0,关联到docker临桥veth上;
离开宿主机时在eth0做源地址转换
container2要想服务被访问,也要在物理机上做目标地址转换,暴露出来
通信种类:
1.容器间通信:同一个pod内,通过lo
2.pod之间通信
3.pod与service通信 # 不在同一网段,通过itable或ipvs通信,切换mode在configmap中切换集群使用哪个
4.service与集群外通信
解决方案:
虚拟网桥,一半在pod,一半在宿主机上接入网桥中,还可以接入真实接口相关的网桥上使用物理桥接的方式
多路复用:MacVLAN
硬件交换:SR-IOV单根虚拟化
配置路径:
/etc/cni/net.d/   k8s会自动加载该路径下的网络插件
flannel优缺点:
简单,但不提供网络策略,进行网络隔离,集群内不同ns可以访问
方法:
使用VxLAN,经过隧道接口封装报文进行通信,支持vxlan\directrouting
host-gw主机网关,使用主机网关,要求同一网段
VxLAN+host-gw:directrouting同一网段使用host-gw,隔路由使用VxLAN
UDP:性能差,旧版本使用
部署:
任何kubelet的node都需要flannel来与pod通信,系统进程\kaemonset方式,每个node一个
配置参数:
Network:flannel使用的CIDR格式的网络地址,用于为pod配置网络功能
         10.244.0.0/16 =》 master:10.244.0.0/24 node01:10.244.1.0/24 ... 10.244.255.0/24
SubnetLen:把network切分子网供各节点使用时,使用多长的掩码进行切分,默认24位
SubnetMin:10.244.10.0/24
SubnetMax:10.244.100.0/24
Backend:vxlan,host-gw,udp
配置示例:
    {"Network":"","Backend":{"Type":"vxlan","Directrouting":true}}
    下载配置文件,修改backend即可
    kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/k8s-manifests/kube-flannel-legacy.yml
    配置修改后需要重启pod才生效

calico:

作为网络插件时,网段是192.168.0.0/16
仅用来部署policy
部署:
    使用k8s自带的etcd来存储数据
    1.如果启用了rbac,需要配置role和绑定
        kubectl apply -f https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/canal/rbac.yaml
    2.kubectl apply -f https://docs.projectcalico.org/v3.1/getting-started/kubernetes/installation/hosted/canal/canal.yaml
应用:
    部署calico后,就可以使用policy控制不同命名空间之间的通信
    Egress出栈控制to,ports
    Ingress入栈控制from,要去的ports
    # 注意policy控制的是对应命名空间下的pod的出入栈
定义networkpolicy:
    apiVersion:networking.k8s.io/v1
    spec:
        egress:
        - ports:
          - port:
            protocal
          to:
          - podSelector:        # 控制pod之间通信
            namespaceSelector:  # 控制名称空间
            ipBlock             # ip块
        ingress:                # - {} 表示允许所有
        - from:
          - ipBlock:
               cidr: 10.244.0.0/16
               except:
               - 10.244.1.2/32
          ports:
          - port:80
            protocol:TCP
        podSelector:            # {}全部pod
            matchLabels:
                app: myapp
        policyTypes:["Egress"]  # 默认定义了都生效,如果没定义的话,默认应用拒绝

调度器scheduler:

默认scheduler调度资源,返回给apiserver,存入etcd
资源限制:
    下限和上限
调度策略:
    1.Predicate预选过程:排除不符合的node
    2.Priority优选:计算各个node的优先级
    3.Select取最高优先级的
Pod选择:
    nodeName
    nodeSelector    影响调度策略的范围
调度方式:
    1.nodeAffinity节点倾向性\亲和性,通过nodeSelector、nodename完成调度
    2.podAffinity\podAntiAffinity pod倾向性,运行在同一个node
    3.Taints污点\污点容忍Tolerations:打上污点后不运行pod,pod要想运行必须容忍所有的污点
预选策略:
    CheckNodeCondition检测node是否正常
    GeneralPredicates包含了几种
        hostname:检测pod对象是否定义了pod.spec.hostname,调度到匹配的主机
        PodFitsHostPorts:pods.spec.containers.ports.hostPort检测端口是否占用
        MatchNodeSelector:pod.spec.nodeSelector
        PodFitsResources:检测node资源是否足够
    NoDiskConflict:没有磁盘冲突,存储卷类型需求(不是默认)
    PodToleratesNodeTaints:检查pod的spec.toleration是否包含node的污点
    PodToleratesNodeNoExecuteTaints:检查
    CheckNodeLabelPresence:默认禁用
    CheckServiceAffinity:倾向于service已有pod的node
    MaxEBSVolumeCount
    MaxGCEPDVolumeCount
    MaxAzureDiskVolumeCount
    CheckVolumeBinding:查看所需pvc的node
    NoVolumeZoneConflict:
    CheckNodeMemoryPressure:
    CheckNodePIDPressure:
    CheckNodeDiskPressure:
    MatchInterPodAffinity:检查pod的亲和性
优选函数:
    least_requested:占用node资源比例最低的
    balanced_resource_allocation:资源占用比率相近
    node_prefer_avoid_pods:根据node注解信息scheduler.alpha.kubernetes.io/preferAvoidPods
    taint_toleration:将pod对象的tolerations与node的taints对比
    selector_spreading:散开pod对象
    InterPodAffinity:pod亲和性
    NodeAffinity:
    (未启动)
    MostRequested:倾向于集中node运行任务,空闲其他node
    NodeLabel:看标签即可,不看值
    ImageLocality:node是否有所需的镜像
    # 看综合得分
使用nodeSelector:
    spec:
        containers:
        nodeSelector:
            app:myapp
使用affinity:
    spec:
      affinity:
        nodeAffinity:
            requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions
                  -  key:zone
                     operator:In
                     value:
                     - foo
                     - bar
            preferredDuringSchedulingIgnoredDuringExecution:
            - preference:
                matchExpressions:
              weight:1-100

    podaffinity可以通过nodeaffinity来实现,但需要编排两次
        podAffinity49472:
            requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                - {key:app,operator:In,value:["myapp"]}
              topologyKey:kubernetes.io/hostname        # 使用这个来区分node位置
            preferredDuringSchedulingIgnoredDuringExecution#类似
                podAffinityTerm
                    labelSelector
                    topologyKey: kubernetes.io/hostname     # 根据节点hostname来判断亲和
    podAntiAffinity类似,效果相反
使用taints:node选择pod
    effect:定义对pod的排斥效果
        NoSchedule仅影响调度、NoExecute不能运行、PreferNoSchedule:柔性影响调度
    管理node污点:
        kubectl taint node name key1=value1:effect1 ...
                taint           key1-
    设置pod的toleration:
        spec:
            tolerations:
            - key:"node-type"
              operator:"Equal"      # Exists
              value:"production"
              effect:"NoSchedule"   # 要准确对应污点的effect,空时匹配所有效果
              # tolerationSeconds:3600
    每次更改pod的toleration后会重新调度

容器的资源需求:

cpu可压缩,内存不可压缩,会OOM
requests和limits,调度pod时看node上运行的pod的requests之和,作为已分配出去的资源
CPU:
    两核四线程为4个逻辑CPU
    1=1000微核心millicores
内存:
    E\P\T\G\M\K
    Ei\Pi\Ti\Gi\Mi\Ki   1024
定义:
    containers:
    - name:
      resources:
        requests:
            cpu:"500m"
            memory:"256Mi"
        limits:
            cpu:
            memory:
Qos:
    Guranteed:每个同时设置了cpu和内存的requests和limits,且相同
    Burstable:至少有一个容器设置了cpu或内存的requests属性,优先终止占用request资源比例大的pod
    BestEffort:没有任何一个容器设置了request或limits属性,最低优先级
HeadpSter:
    kubelet中采集node资源情况的是内置的cAdvisor
    HeadpSter收集各个node的cAdvisor,缓存一段时间
    持久历史放在InfluxDB,通过grafana进行可视化
部署influxdb:
    https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/influxdb/influxdb.yaml
    wget下载,修改version为apps/v1,修改nodeselector,修改存储卷,services
部署heapster:
    https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/rbac/heapster-rbac.yaml
    https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/influxdb/heapster.yaml
    先进行role绑定,再部署serviceaccount\deployment
    修改version为apps/v1,修改nodeselector
    command连接到influxdb,指定source=kubernetes:https://kubernetes.default定义了如何连接apiserver
    --sink=influxdb:http://monitoring-influxdb.kube-system.svc:8086指向influxdb的service
部署grafana:
    https://raw.githubusercontent.com/kubernetes-retired/heapster/master/deploy/kube-config/influxdb/grafana.yaml
    wget,修改apiversion为apps/v1,添加对应的selector,修改service的type为nodePort
    https证书自动挂载本地的/etc/ssl/certs
    添加dashborad即可可视化
    如果经过nginx代理,grafana可能会找不到静态文件,需要修改homepage之类的。
    hostNetwork为true,直接访问其他端口3000,而不是更改url则没问题
命令行查看:
    kubectl top node\pod

资源指标与自定义指标:

一些HPA、top命令早期依赖heapster,仅支持内存和cpu指标
heapster为了适配各种存储后端,整合了多个适配器,更新缓慢,导致代码大
新一代依靠metrics-server这个API server服务与资源指标,部署为pod
自定义指标:premetheus,组件k8s-prometheus-adapter
新一代架构:
    核心指标流水线:由kubelet、metrics-server以及API server提供的api组成,CPu累积使用率、内存实时使用率,pod资源占用以及容器磁盘使用率
    监控流水线:用于从系统收集各种指标数据并提供终端用户、存储系统以及HPA,包含许多核心指标和非核心指标。
metrics-server提供资源指标,由kube-aggregator聚合metrics-server和apiserver的原生指标,通过/apis/metrics.k8s.io/v1beta1
部署metrics-server:
    https://github.com/kubernetes/kubernetes/tree/master/cluster/addons/metrics-server
    for file in auth-delegator.yaml auth-reader.yaml metrics-apiserver.yaml  metrics-server-deployment.yaml 
    metrics-server-service.yaml resource-reader.yaml;do wget https://raw.githubusercontent.com/kubernetes/kubernetes/master/cluster/addons/metrics-server/$file;done
    apply后kubectl api-versions即可查看新url
    查看metrics资源:
        master下用kubectl proxy --port=8080
        然后curl http://localhost:8080/apis/metrics.k8s.io/v1beta1
    问题:获取不了数据
        1.修改command:改默认10255为10250
        默认通过http的kubernetes.summary_api的默认链接来访问,但被默认禁用了
        /metris-server --source=kubernetes.summary_api:https://kubernetes.default?kubeletHttps=true&kubeletPort=10250&insecure=true
        # 新版的不用修改了
        2.修改clusterRole的resources添加一个nodes/stats
部署prometheus获取其他指标:
    Prometheus为server,client为node_exporter采集系统数据,其他数据需要如mysql_exporter
    通过PromQL提供restful接口数据,经过Prometheus adapter转为metrics api的数据
    git clone https://github.com/iKubernetes/k8s-prom.git
    1.部署node-exporter,daemonset的形式,采集node的数据
        kubectl apply -f ./k8s-prom/node_exporter/
    2.部署prometheus以及相应的serviceaccount、rolebinding、service,即可访问webui
        默认监听9090
        将service端口30090加到nginx中,但还是有非根目录导致404静态文件的问题
        kubectl apply -f ./k8s-prom/prometheus/
        在启动的时候设置web.external-url使用下面的命令:
            ./prometheus --web.external-url=prometheus --config.file=prometheus.yml
        nginx配置为 location /prometheus       proxy_pass http://prometheus.prom.svc.cluster.local:9090/prometheus
        登录网页即可查看指标
        curl http://localhost:9091/prometheus/api/v1/label/__name__/values # grafana通过这个接口来查询metrics
    3.部署kube-state-metrics转为metrics api指标
        ./k8s-prom/kube-state-metrics/
    4.部署kube-prometheus-adapter,自制k8s签署的证书cm-adapter-serving-certs,生成generic secret供https使用
        cd /etc/kubernetes/pki/
        (umask 077;openssl genrsa -out serving.key 2048)
        openssl req -new -key serving.key -out serving.csr -subj "/CN=serving"
        openssl x509 -req -in serving.csr -CA ./ca.crt -CAkey ./ca.key -CAcreateserial -out serving.crt -days 3650
        kubectl create secret generic cm-adapter-serving-certs --from-file=./serving.crt --from-file=serving.key -n prom
        apply -f ./k8s-prom/k8s-prometheus-adapter/ # deploy取自https://github.com/DirectXMan12/k8s-prometheus-adapter/tree/master/deploy/manifests 
    即可看到自定义的custom.metrics.k8s.io/v1beta1
        curl http://localhost:8080/apis/custom.metrics.k8s.io/v1beta1
    配合HPA或grafana定义数据源导入模板即可
        应用grafana,注释掉env中的influxdb,修改namespace
        # 进入所在pod,修改配置/etc/grafana/grafana.ini,修改root_url = http://apulis-china-infra01.sigsus.cn/grafana
        修改yaml中的env的GF_SERVER_ROOT_URL为/grafana/     # 进入pod查看root_url没变
        nginx代理数据源为proxy_pass http://prometheus.prom.svc.cluster.local:9090/;
        在grafana dashborad搜索kubernetes模板,下载json,在home导入即可
        # 数据源也可以配置
        如何调试:
            页面登录账号后,就可以编辑pannel,添加数据源等,在pannel中调试数据源的指标,点击Query Inspector即可显示url
            这个url可以前端请求来获取资源数据
HPA:
    自动伸缩容
    kubectl autoscale deployment myapp --min=1 --max=8 --cpu-percent=60 # 默认使用v1控制器
    进行请求压测install httpd-utils
        ab -c 1000 -n 500000 http://xxx
    v2控制器可以使用其他评估指标
        kind:HorizontalPodAutoscaler
        metadata:
        spec:
            scaleTargetRef:
                apiversion:apps/v1
                kind:Deployment
                name:myapp
            minReplicas:1
            maxReplicas:8
            metrics:
            - type:Resource
              resource:
                name:cpu
                targetAverageUtilization:55
            - type:resource
              resource:
                name:memory
                targetAverageValue:50Mi         # v1不支持内存
        自定义指标输出:如pod的最大请求数,hpa收集
            - type:Pods
              pods:
                metricName:http_requests
                targetAverageValue:800m     # 个

Helm入门:

命令行工具,不直接交互apiserver,而是Tiller,运行为pod
下载需要的chart到本地,不同的配置文件成为不同的release
helm支持chart版本更新,查询和卸载等操作,将配置清单可复用
核心术语:
    Chart:一个helm程序包
    Repository:仓库
    Release:特定的Chart部署于目标集群上的一个实例
架构:
    chart->config->release
    tiller接收helm发送的charts和config,合并为release
安装:
    wget https://get.helm.sh/helm-v2.9.1-linux-amd64.tar.gz --no-check-certificate
    helm使用kubectl的配置文件来访问apiserver
    配置role
        apiVersion: v1
        kind: ServiceAccount
        metadata:
          name: tiller
          namespace: kube-system
        ---
        apiVersion: rbac.authorization.k8s.io/v1
        kind: ClusterRoleBinding
        metadata:
          name: tiller
        roleRef:
          apiGroup: rbac.authorization.k8s.io
          kind: ClusterRole
          name: cluster-admin
        subjects:
        - kind: ServiceAccount
          name: tiller
          namespace: kube-system
    安装tiller:
        helm init --service-account tiller
        镜像下载不了,kubectl edit deploy tiller-deploy -n kube-system改为jinxiaoyuan/tiller
        # 或者先pull镜像,tag
        # docker pull jinxiaoyuan/tiller:v2.9.1
        sudo apt install socat
仓库:
    https://hub.helm.sh/
    helm repo update
    helm search redis
    heml inspect stable/redis
    helm install --name myredis -f value.yaml stable/redis
    helm delete/status/history xx

    create/fetch/get(不解包)/package/verify
目录结构:
    xxx:
        Chart.yaml  # helm本身维护的chart元信息
        README.md
        charts:     # 放置依赖
        requirements.yaml  
        templates
            _helpers.tpl
            xxx.yaml    # 大量利用go模板语法生成字段
        values-production.yaml 
        values.yaml     # 配置变量,install -f可以指定自定义变量文件
自定义chart:
    go模板语法:{{.Values.imageRegistry}}  表示引用values.yaml文件的第一层次字段imageRegistry
        {{default "" .Values.imageRegistry}}
    helm create myapp编辑好values
    helm lint myapp
    helm serve 
    helm package myapp
    helm search myapp
    helm install --name myapp local/myapp
    helm status myapp 
    helm delete --purge myapp

日志系统:

部署方案:

1.sidecar,不建议一个pod超过两个容器
2.部署为daemonset

ELK:

使用每个node的fluentd+logstash server+elastic master接收请求+data处理后端

部署:

helm fetch stable/elasticsearch
修改values文件
helm install --name els --namespace=prom -f values.yaml stable/elasticsearch
运行测试程序:
    kubectl run cirror --rm -it -image=cirros -- /bin/bash
    curl elasticd的域名:9200/_cat/nodes
部署fluentd每个node收集日志:
    helm fetch stable/fluentd-elasticsearch
    填写es域名和9200,如果master要收集要填写tolerations,要监控填写prometheus
    helm install --name flu --namespace=prom -f values.yaml stable/fluentdel-asticsearch
部署kibana:
    helm etch stable/kibana
    填写es地址
    helm install --name kib --namespace=prom -f values.yaml stable/kibana

Paas概述:

CI(Continuous Integration)\CD\CD
发布过程:
    developer->git->Jenkins/CI->application->docker build->docker hub->k8s 
    developer->git->docker file->docker build->docker hub->k8s 
    developer用python写一段代码,实现自动发布到k8s
Paas:
    openshit:包含一整套k8s以及日志监控、自动发布上线的os

命名空间:

示例:

kubectl get ns default -o yaml --export
---
apiVersion:v1
kind:Namespace
metadata:
    name:develop    # 其他的createTime\selfLink会自动生成
spec:
    finalizers:
        - kunernetes    # 负责回收,可以不定义

搭建DLWS:

用到的服务:

PXE预启动执行环境,提供一种网络接口启动计算机的机制
重定向服务(DHCP代理)
TFTP协议下载到内存

资源:

一台服务器时可以起docker在里面部署本机为master,部署机本身始终没有启动任何服务,都是通过脚本ssh到远程执行命令
(按道理可以本机部署本机?)
域名注册和dns解析(阿里云购买域名后免费提供解析)
更新hostname为子域名

流程:

前置:

如果部署过kubeadm,记得apt remove\autoremove清空,然后重新./deploy.py -y build

1.在部署机ubuntu上安装基本所需工具

如果是docker内部署本机,sudo docker run -v /var/run/docker.sock:/var/run/docker.sock -v ~/:/home/dlwsadmin -it ubuntu:16.04
sh ../../install_prerequisites.sh
两个node一个master:
    apt install net-tools,vim,sudo,openssh-server
    sudo systemctl start ssh
    passwd
    vim /etc/ssh/sshd_config    #PermitRootLogin prohibit-password为PermitRootLogin yes,再运行密码登录,重启ssh
    etc/init.d/ssh start
    apt-get  install openssh-server
    最后因为docker没有bus,进行不下去

2.配置集群config.yaml,配置id,domain,machine

3.如果系统未安装,部署机可以安装PXE

4.执行./deploy.py -y build

wget http://ccsdatarepo.westus.cloudapp.azure.com/data/containernetworking/cni-amd64-v0.5.2.tgz
mkdir ./deploy/bin && mv cni-amd64-v0.5.2.tgz ./deploy/bin/

5.将账号密码输入echo dlwsadmin > ./deploy/sshkey/rootpasswd ./deploy/sshkey/rootuser以便部署机使用账号密码访问

6.安装key ./deploy.py sshkey install

7.查看key是否安装成功./deploy.py execonall sudo ls -al

8.远程为node安装基本工具./deploy.py runscriptonall ./scripts/prepare_ubuntu.sh

./deploy.py execonall sudo usermod -aG docker dlwsadmin

9.下载镜像

./deploy.py execonall docker pull dlws/pause-amd64:3.0
./deploy.py execonall docker tag  dlws/pause-amd64:3.0 gcr.io/google_containers/pause-amd64:3.0

10.开始部署kubernets

./deploy.py -y deploy            # 如果部署失败,systemctl status kubelet查看原因,如/etc/hosts没有加入短域名,端口1443未外网开放
./deploy.py -y updateworker        # 不同集群的机器作为worker的话,执行这个没有成功加入。如果集群内两台机器,则稍等后可以看到node
./deploy.py labelworker
./deploy.py -y kubernetes labelservice        # 根据域名来label node,如果域名不一致,会失败
在master上启动workload 
    ./deploy.py -y kubernetes uncordon
创建软链
    sudo ln -s /home/ubuntu/QianJiangYuan/src/ClusterBootstrap/deploy/bin/kubectl /usr/bin/kubectl

11.挂载分享文件盘

./deploy.py mount
./deploy.py mount stop

12.deploy nvidia-device

准备:安装显卡驱动
./deploy.py kubectl label node apulis-sz-dev-worker01 gpuType=nvidia
./deploy.py kubectl create -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v1.9/nvidia-device-plugin.yml
# v1.9版本与kubelet相关,要看版本,k8s版本1.15以上用v1.11
    sudo apt-get install nvidia-container-runtime
    distribution=$(. /etc/os-release;echo $ID$VERSION_ID) \
       && curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add - \
       && curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
    curl -s -L https://nvidia.github.io/nvidia-container-runtime/experimental/$distribution/nvidia-container-runtime.list | sudo tee /etc/apt/sources.list.d/nvidia-container-runtime.list
    apt-get update
    apt-get install -y nvidia-docker2
    cat /proc/driver/nvidia/version
    设置/etc/docker/daemon.json
        {
            "default-runtime""nvidia",
            "runtimes": {
                "nvidia": {
                    "path""/usr/bin/nvidia-container-runtime",
                    "runtimeArgs": []
                }
            },
            "registry-mirrors": ["https://expuzg6d.mirror.aliyuncs.com"]
        }
# 遇到too old to support healtchecking with error: %!s(MISSING). Marking it unhealthy
    给plugin添加env DP_DISABLE_HEALTHCHECKS=xids

13.部署各个service

./deploy.py webui
./deploy.py docker push restfulapi
./deploy.py docker push webui3
./deploy.py docker push init-container
./deploy.py docker push prometheus        # 监控组件
./deploy.py docker push grafana
./deploy.py docker push collectd
./deploy.py docker push influxdb
./deploy.py docker push nginx
./deploy.py nginx fqdn
./deploy.py nginx webui3
./deploy.py nginx config    # 复制文件到/etc/nginx/conf.other
./deploy.py setconfigmap
./deploy.py kubernetes start mysql jobmanager2 restfulapi2 webui3 monitor nginx custommetrics repairmanager2 openresty
    # 会以集群name为前缀拉起image,修改config.yaml可以生效
    # nginx的certbot需要解析域名,如果是local域名,需要配置/etc/resolv.conf为本地,如果是公网域名,/etc/resolv.conf为公开dns地址即可

14.清理集群

./deploy.py cleanworker
./deploy.py cleanmasteretcd
./deploy.py clean

./deploy.py kubeadm reset

kubeadm部署方式

10. ./deploy.py --verbose kubeadm init

11. ./deploy.py --verbose kubeadm join

其余相同

修改apiserver的nodeport的范围
vim /etc/kubernetes/manifests/kube-apiserver.yaml
增加参数- --service-node-port-range=1-65535
# 好像不用重启
systemctl daemon-reload
systemctl restart kubelet

备份配置文件:

./deploy.py backup [backup_file_prefix] [password]        # 前缀
./deploy.py restore [backup_file] [password]    
./deploy.py restorebin        # 第二个command为restore的地方会被第一个拦截,修改为restorebin
    需要用到镜像
        docker pull rancher/hyperkube:v1.16.9-rancher1
        docker tag rancher/hyperkube:v1.16.9-rancher1 gcr.azk8s.cn/google-containers/hyperkube:v1.15.2
即可正常执行kubernetes命令

HA:

官方文档:

https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/

1.利用vip镜像生成/etc/kubernetes/manifests/vip.yaml

2.通过命令生成ha初始集群

kubeadm init --v=8 --control-plane-endpoint=10.31.3.207 --kubernetes-version=v1.18.2 --upload-certs

3.加入剩余的master和worker

kubeadm init --v=8 phase upload-certs --upload-certs
kubeadm token create
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
kubeadm join --v=8 --token %s %s:%s --discovery-token-ca-cert-hash sha256:%s --control-plane --certificate-key %s

sudo kubeadm join --v=8 --token %s %s:%s --discovery-token-ca-cert-hash sha256:%s

vip原理:

docker容器先检测本地的物理接口eno1,增加inet6,然后容器能够ping通后,生成vip到具体的master上,局域网内可以访问这个vip

二进制搭建kubernetes集群:

微软方式:

生成ca证书
    mkdir -p ca
    openssl genrsa -out ca/ca-key.pem 2048
    openssl req -x509 -new -nodes -key ca/ca-key.pem -days 10000 -out ca/ca.pem -subj "/CN=kube-ca"
生成kubelet证书:
    编辑文件openssl-kubelet.cnf:
        [req]
        req_extensions = v3_req
        distinguished_name = req_distinguished_name
        [req_distinguished_name]
        [ v3_req ]
        basicConstraints = CA:FALSE
        keyUsage = nonRepudiation, digitalSignature, keyEncipherment
        subjectAltName = @alt_names
        [alt_names]
        DNS.1 = kubernetes
        DNS.2 = kubernetes.default
        DNS.3 = kubernetes.default.svc
        DNS.4 = kubernetes.default.svc.cluster.local
        DNS.5 = *.sigsus.cn
        DNS.6 = *.redmond.corp.microsoft.com
        DNS.7 = *.corp.microsoft.com
    mkdir -p kubelet
    openssl genrsa -out kubelet/apiserver-key.pem 2048
    openssl req -new -key kubelet/apiserver-key.pem -out kubelet/apiserver.csr -subj "/CN=kube-apiserver" -config openssl-kubelet.cnf
    openssl x509 -req -in kubelet/apiserver.csr -CA ca/ca.pem -CAkey ca/ca-key.pem -CAcreateserial -out kubelet/apiserver.pem -days 3650 -extensions v3_req -extfile openssl-kubelet.cnf
    cp ca/ca.pem kubelet
    rm ca/ca.srl
    rm kubelet/apiserver.csr
生成etcd证书
    mkdir -p etcd
    openssl genrsa -out etcd/etcd-key.pem 2048
    openssl req -new -key etcd/etcd-key.pem -out etcd/etcd.csr -subj "/CN=kube-apiserver" -config openssl-etcd.cnf
    openssl x509 -req -in etcd/etcd.csr -CA ca/ca.pem -CAkey ca/ca-key.pem -CAcreateserial -out etcd/etcd.pem -days 3650 -extensions v3_req -extfile openssl-etcd.cnf
    cp ca/ca.pem etcd
    rm etcd/etcd.csr
复制到指定目录下:
    mkdir -p /etc/etcd/ssl
    cp etcd/ca.pem /etc/etcd/ssl
    cp etcd/etcd.pem /etc/etcd/ssl
    cp etcd/etcd-key.pem /etc/etcd/ssl
配置etcd3 service:
    编辑文件/etc/systemd/system/etcd3.service
        [Service]
        ExecStart=/usr/bin/docker run -v /usr/share/ca-certificates/mozilla:/etc/ssl/certs -v /etc/etcd/ssl:/etc/etcd/ssl -v /var/etcd:/var/etcd -p 2379:2379 -p 2380:2380 \
          --net=host \
          --name etcd3 dlws/etcd:3.1.10 /usr/local/bin/etcd \
          -name dlworkspace-etcd1 \
          -initial-cluster dlworkspace-etcd1=https://worker.sigsus.cn:2380 \
          -initial-cluster-state new \
          -initial-cluster-token 536eea5f-280e-453e-81a3-6198e66fb56d \
          -advertise-client-urls https://worker.sigsus.cn:2379 \
          -listen-client-urls https://0.0.0.0:2379 \
          -initial-advertise-peer-urls https://worker.sigsus.cn:2380 \
          -listen-peer-urls https://0.0.0.0:2380 \
          -data-dir /var/etcd/data \
          -client-cert-auth \
          -trusted-ca-file=/etc/etcd/ssl/ca.pem \
          -cert-file=/etc/etcd/ssl/etcd.pem \
          -key-file=/etc/etcd/ssl/etcd-key.pem \
          -peer-client-cert-auth \
          -peer-trusted-ca-file=/etc/etcd/ssl/ca.pem \
          -peer-cert-file=/etc/etcd/ssl/etcd.pem \
          -peer-key-file=/etc/etcd/ssl/etcd-key.pem
        Restart=always
        RestartSec=5
        [Install]
        WantedBy=multi-user.target
    编辑文件/opt/etcd_ssl.sh
        #ETCD_VER=v3.3.2 && DOWNLOAD_URL=https://github.com/coreos/etcd/releases/download && \
        #curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz && \
        #mkdir -p /tmp/test-etcd && \
        #tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /tmp/test-etcd --strip-components=1 && \
        #mkdir -p /opt/bin && \
        #mv /tmp/test-etcd/etcd /opt/bin && \
        #mv /tmp/test-etcd/etcdctl /opt/bin
        #rm -r /tmp/test-etcd
        docker rm -f etcd3
        systemctl daemon-reload
        systemctl start etcd3
        systemctl enable etcd3
启动etcd3服务
    chmod +x /opt/etcd_ssl.sh
    systemctl start etcd3
    这一步尝试去拉取镜像,然后启动容器,监听端口2379
    等待服务起来:
        curl  --cacert /etc/etcd/ssl/ca.pem --cert /etc/etcd/ssl/etcd.pem --key /etc/etcd/ssl/etcd-key.pem "https://127.0.0.1:2379/v2/keys"
设置network范围:
    curl  --cacert /etc/etcd/ssl/ca.pem --cert /etc/etcd/ssl/etcd.pem --key /etc/etcd/ssl/etcd-key.pem -X PUT -d "value={\"Network\":\"10.2.0.0/16\",\"Backend\":{\"Type\":\"vxlan\"}}" "https://127.0.0.1:2379/v2/keys/coreos.com/network/config"

生成apiserver证书
    编辑文件openssl-apiserver.cnf:
        [req]
        req_extensions = v3_req
        distinguished_name = req_distinguished_name
        [req_distinguished_name]
        [ v3_req ]
        basicConstraints = CA:FALSE
        keyUsage = nonRepudiation, digitalSignature, keyEncipherment
        subjectAltName = @alt_names
        [alt_names]
        DNS.1 = kubernetes
        DNS.2 = kubernetes.default
        DNS.3 = kubernetes.default.svc
        DNS.4 = kubernetes.default.svc.cluster.local
        DNS.5 = worker.sigsus.cn
        IP.0 = 10.3.0.1
        IP.1 = 127.0.0.1
        IP.2 = 127.0.1.1
    mkdir -p apiserver
    openssl genrsa -out apiserver/apiserver-key.pem 2048
    openssl req -new -key apiserver/apiserver-key.pem -out apiserver/apiserver.csr -subj "/CN=kube-apiserver" -config openssl-apiserver.cnf
    openssl x509 -req -in apiserver/apiserver.csr -CA ca/ca.pem -CAkey ca/ca-key.pem -CAcreateserial -out apiserver/apiserver.pem -days 3650 -extensions v3_req -extfile openssl-apiserver.cnf
    cp ca/ca.pem apiserver
    cp ca/ca-key.pem apiserver
    rm apiserver/apiserver.csr
生成kubernetes证书:
    执行脚本./gencerts_aggregator.sh,利用easyrsa生成pki/private/ca.key和pki/ca.crt,cfssl和cfssljson基于ca证书生成pki/issued/proxy-client.crt和pki/private/proxy-client.key,用于apiserver组件--proxy-client-cert-file
    官方kubeadm的yaml除了--proxy-client-cert-file还有--kubelet-client-certificate等,需要的crt和key更多。

下载kubectl二进制文件
    可以从镜像获取
    docker create -it --name test dumb008/hyperkube:1.15.0
    docker cp --follow-link=true test:/kubelet /opt/bin/kubelet
    docker cp --follow-link=true test:/kubectl /usr/bin/kubectl
生成kubelet.service服务文件:
    [Service]
    Environment=KUBELET_VERSION=v1.5.2_coreos.0
    Environment="RKT_OPTS=--uuid-file-save=/var/run/kubelet-pod.uuid \
      --volume var-log,kind=host,source=/var/log \
      --mount volume=var-log,target=/var/log \
      --volume dns,kind=host,source=/etc/resolv.conf \
      --mount volume=dns,target=/etc/resolv.conf"

    ExecStartPre=/bin/bash -c 'mkdir -p /etc/kubernetes/manifests'
    ExecStartPre=/bin/bash -c 'mkdir -p /var/log/containers'
    #ExecStartPre=-/usr/bin/rkt rm --uuid-file=/var/run/kubelet-pod.uuid
    ExecStartPre=/bin/bash -c 'if lspci | grep -qE "[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F].[0-9] (3D|VGA compatible) controller: NVIDIA Corporation.*"; then if [ -e /etc/systemd/system/nvidia-docker.service ] ; then until wget -q -O - http://localhost:3476/gpu/info ; do /bin/echo "waiting for nvidia-docker..." ; /bin/sleep 2 ; done fi fi'
    #
    # https://github.com/kubernetes/kubernetes/issues/48937
    # Glusterfs currently need docker-disable-shared-pid option, will evaluate in future kubernete release
    #
    # https://kubernetes.io/docs/tasks/manage-gpus/scheduling-gpus/
    ExecStart=/opt/bin/kubelet \
      --volume-plugin-dir=/etc/kubernetes/volumeplugins \
      --kubeconfig=/etc/kubernetes/worker-kubeconfig.yaml \
      --register-with-taints=node-role.kubernetes.io/master=:NoSchedule \
      --pod-infra-container-image=dlws/pause-amd64:3.0 \
      --container-runtime=docker \
      --feature-gates="DevicePlugins=true,PodShareProcessNamespace=true" \
      --pod-manifest-path=/etc/kubernetes/manifests \
      --network-plugin=cni \
      --cluster_dns=10.3.0.53 \
      --cluster_domain=cluster.local
    #ExecStop=-/usr/bin/rkt stop --uuid-file=/var/run/kubelet-pod.uuid
    Restart=always
    RestartSec=10
    [Install]
    WantedBy=multi-user.target
复制证书文件、bin文件、kube系统的yaml文件以及其他文件到master
    /etc/kubernetes/ssl/ca-key.pem
    /etc/kubernetes/ssl/ca.pem
    /etc/kubernetes/ssl/apiserver.pem
    /etc/kubernetes/ssl/apiserver-key.pem
    ...
    kube-apiserver.yaml                     # 里面的image为hyperkube,但可以参考官方的yaml文件
    kube-controller-manager.yaml 
    kube-scheduler.yaml
3.启动kubelet
    sudo cp /etc/kubernetes/ssl/ca.pem /etc/ssl/etcd/ca.pem
    sudo cp /etc/kubernetes/ssl/ca-key.pem /etc/ssl/etcd//ca-key.pem
    sudo cp /etc/kubernetes/ssl/apiserver.pem /etc/ssl/etcd/apiserver.pem
    sudo cp /etc/kubernetes/ssl/apiserver-key.pem /etc/ssl/etcd/apiserver-key.pem
    sudo chmod +x /opt/bin/* 
    sudo systemctl daemon-reload
    sudo systemctl stop kubelet
    sudo systemctl start kubelet
    sudo systemctl start rpc-statd
    sudo systemctl enable kubelet
kubelet启动后,查看status是否正常,docker ps查看manifests的几个组件是否启动
    systemctl status kubelet 
    journalctl -xeu kubelet查看具体报错原因,比如image拉取问题
    docker ps 
    注:kubelet维护kube-apiserver kube-controller-manager kube-scheduler的正常运行,另外一种做法就是将kube-apiserver kube-controller-manager kube-scheduler单独维护service,无需kubelet来维护,也可以用kubectl
        kubelet此外还负责pod管理、节点管理等
等待8080端口(scheduler监听)启动后,kubectl即可用
    kubectl get node 
    kubectl apply 
通过kubectl和yaml启动weave、dns-addon、kube-proxy
    kubectl apply -f /opt/addons/kube-addons/weave.yaml --validate=false
    kubectl apply -f /opt/addons/kube-addons/dns-addon.yml --validate=false
    kubectl apply -f /opt/addons/kube-addons/kube-proxy.json --validate=false

问题: 
    1.weave启动失败,获取kubernetes service失败Get https://10.3.0.1:443/api/v1/nodes: dial tcp 10.3.0.1:443: i/o timeout
        原因1:
            发现apiserver组件log异常,Resetting endpoints for master service "kubernetes" to [127.0.0.1]
            原来是yaml里面的--advertise-address指定了127.0.0.1
        原因2:
            kube-proxy是否正常启动,它负责了iptables的建立,实现service与pod间的iptables调度或ipvs调度、即pod与集群间通信
    2.kube-dns服务不好用 
        dns-addon组件log是否异常,然后定位本地的systemd-resolved是否启动。

如何clean集群:
    sudo systemctl stop kubelet
    sudo systemctl stop etcd3
    sudo timeout 10 docker rm -f $(docker ps -a | grep 'k8s_kube\|k8s_POD\|k8s_' | awk '{print $1}')
    sudo rm -r /etc/kubernetes
    sudo rm -r /etc/ssl/etcd
    rm -r /var/etcd/data
    rm -r /etc/etcd/ssl
    sudo rm -r /etc/flannel
    sudo rm -r /opt/addons
    sudo systemctl daemon-reload

二进制做法:

1.安装chrony时间服务

apt remove -y ntp
apt install chrony
配置一下主master上的/etc/chrony/chrony.conf,修改一下server地址、allow
然后配置其他节点的pool为第一个master

2.生成CA根证书和私钥

安装cfssl:
apt install golang-cfssl
配置文件ca-config.json、ca-csr.json,里面不包含具体信息
执行cfssl gencert -initca ca-csr.json|cfssljson -bare ca生成ca.csr、ca-key.pem、ca.pem

3.生成对应的数字证书和私钥用于kubectl、proxy、manager、scheduler

设置kubectl
    配置admin-csr.json签名请求,里面不包含具体ip信息,只有admin这个用户名
    签发数字证书和私钥,生成admin.csr、admin-key.pem、admin.pem
        cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin
    设置集群参数kubectl config set-cluster DLWS --certificate-authority=/root/kubernetes/ssl/ca.pem --embed-certs=true --server=https://192.168.1.184:6443    # 没有指定路径的话,生成文件/root/.kube/config
    设置客户端认证参数kubectl config set-credentials admin --client-certificate=/root/kubernetes/ssl/admin.pem --embed-certs=true --client-key=/root/kubernetes/ssl/admin-key.pem # --embed-certs为true,将证书写入文件
    设置上下文参数kubectl config set-context context-DLWS-admin --cluster=DLWS --user=admin
    选择默认上下文kubectl config use-context context-DLWS-admin
    确认:kubectl config view
设置proxy,作为该组件的kubeconfig以获取集群资源:
    准备文件kube-proxy-csr.json,里面不包含具体信息
    签发: 
        cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
    设置集群参数kubectl config set-cluster DLWS --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.1.184:6443 --kubeconfig=./kube-proxy.kubeconfig
    设置客户端认证参数kubectl config set-credentials kube-proxy --client-certificate=kube-proxy.pem --embed-certs=true --client-key=kube-proxy-key.pem --kubeconfig=./kube-proxy.kubeconfig
    设置上下文参数kubectl config set-context default --cluster=DLWS --user=kube-proxy --kubeconfig=./kube-proxy.kubeconfig
    选择默认上下文kubectl config use-context default --kubeconfig=./kube-proxy.kubeconfig
设置kube-controller-manager,作为该组件的kubeconfig以获取集群资源
    准备文件kube-controller-manager-csr.json,里面不包含具体信息
    签发: 
        cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-controller-manager-csr.json | cfssljson -bare kube-controller-manager
    设置集群参数kubectl config set-cluster DLWS --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.1.184:6443 --kubeconfig=./kube-controller-manager.kubeconfig
    设置客户端认证参数kubectl config set-credentials system:kube-controller-manager --client-certificate=kube-controller-manager.pem --embed-certs=true --client-key=kube-controller-manager-key.pem --kubeconfig=./kube-controller-manager.kubeconfig
    设置上下文参数kubectl config set-context default --cluster=DLWS --user=system:kube-controller-manager --kubeconfig=./kube-controller-manager.kubeconfig
    选择默认上下文kubectl config use-context default --kubeconfig=./kube-controller-manager.kubeconfig
设置kube-scheduler,作为该组件的kubeconfig以获取集群资源:
    准备文件kube-scheduler-csr.json,里面不包含具体信息
    签发: 
        cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kube-scheduler-csr.json | cfssljson -bare kube-scheduler
    生成config文件kubectl config set-cluster DLWS --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.1.184:6443 --kubeconfig=./kube-scheduler.kubeconfig
    设置客户端认证参数kubectl config set-credentials system:kube-scheduler --client-certificate=kube-scheduler.pem --embed-certs=true --client-key=kube-scheduler-key.pem --kubeconfig=./kube-scheduler.kubeconfig
    设置上下文参数kubectl config set-context default --cluster=DLWS --user=system:kube-scheduler --kubeconfig=./kube-scheduler.kubeconfig
    选择默认上下文kubectl config use-context default --kubeconfig=./kube-scheduler.kubeconfig
复制到节点的对应目录:
    cp kube-proxy.kubeconfig kube-controller-manager.kubeconfig kube-scheduler.kubeconfig /etc/kubernetes/   # 如果复制到其他master,需要替换掉其中的server ip

4.下载bin文件,生成etcd证书和私钥,systemctl维护etcd服务(可以宿主机上后台进程)

ETCD_VER=v3.4.13
wget --tries=10 https://github.com/etcd-io/etcd/releases/download/$ETCD_VER/etcd-$ETCD_VER-linux-amd64.tar.gz
tar zxf etcd-$ETCD_VER-linux-amd64.tar.gz && cd etcd-$ETCD_VER-linux-amd64 && cp etcd etcdctl /opt/kube/bin
准备文件etcd-csr.json,里面包含具体ip信息hosts
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes etcd-csr.json | cfssljson -bare etcd
cp etcd-key.pem etcd.pem /etc/etcd/ssl/
mkdir /etc/kubernetes/ssl/
cp ca.pem ca-key.pem ca-config.json /etc/kubernetes/ssl/
准备etcd的service文件,复制到/etc/systemd/system/etcd.service
mkdir /var/lib/etcd
systemctl enable etcd
systemctl daemon-reload && systemctl restart etcd
服务起来后,监听端口2379,用于与client端交互,监听peer端口2380用于etcd内部交互

5.下载二进制文件,生成k8s证书,创建aggregator proxy相关证书,然后systemctl维护kube-apiserver kube-controller-manager kube-scheduler(可以宿主机上后台进程),kubectl即可用

K8S_VER=v1.18.0
wget --tries=10 https://dl.k8s.io/$K8S_VER/kubernetes-server-linux-amd64.tar.gz
tar zxf kubernetes-server-linux-amd64.tar.gz && cd kubernetes/server/bin && cp kube-apiserver kube-controller-manager kube-scheduler kubelet kube-proxy kubectl /opt/kube/bin
mkdir /opt/cni/bin
准备cni插件,必须,kubeadm安装的话自带,二进制的话必须手动复制(cni插件是给coredns用的,默认读取/opt/cni/bin/路径)
    CNI_VER=v0.8.7
    wget --tries=10 https://github.com/containernetworking/plugins/releases/download/$CNI_VER/cni-plugins-linux-amd64-$CNI_VER.tgz
    tar zxf cni-plugins-linux-amd64-$CNI_VER.tgz && cp bridge flannel host-local loopback portmap tuning /opt/cni/bin
准备文件kubernetes-csr.json,填上允许的ip,用于apiserver来决定从哪些ip(即kubeconfig中的server)可以访问它(如果用了vip,则建议除了各master的ip,加上vip)
    cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kubernetes-csr.json | cfssljson -bare kubernetes
准备aggregator-proxy-csr.json,不包含ip信息
    cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes aggregator-proxy-csr.json |
 cfssljson -bare aggregator-proxy
准备三个系统组件的service文件
    cp kube-apiserver.service kube-controller-manager.service kube-scheduler.service /etc/systemd/system/   
    复制相应的证书
    cp kubernetes-key.pem kubernetes.pem /etc/kubernetes/ssl/
    cp aggregator-proxy-key.pem aggregator-proxy.pem /etc/kubernetes/ssl/
    cp admin-key.pem admin.pem /etc/kubernetes/ssl/
systemctl enable kube-apiserver kube-controller-manager kube-scheduler
systemctl daemon-reload
systemctl start kube-apiserver kube-controller-manager kube-scheduler
各个状态均为running即可。
6.master部署kubelet和kube-proxy,然后kubectl get node信息才获取到。

7.部署网络组件、dns(顺序可选最后),node变为ready

kubectl apply -f weave-role.yaml
kubectl apply -f weave.yaml
删除原有cni配置/etc/cni/net.d/10-default.conf 
ip link set mynet0 down
ip link del mynet0
重启docker、kubelet、kube-proxy
准备coredns文件
kubectl apply -f coredns.yaml

8.kubelet证书和kubeconfig,kube-proxy证书和kubeconfig,worker节点复制证书、部署kubelet和kube-proxy

准备文件kubelet-csr.json,包含节点具体ip信息
    证书除了用于生成kubeconfig,还用于kubelet的tlsCertFile。tlsCertFile包含的ip信息也会用于kubelet来与apiserver(ca证书)通信验证hosts,所以新的节点ip也要更新。
    否则,Error from server: Get https://192.168.1.153:10250/containerLogs/kube-system/kube-vip-3/kube-vip?follow=true: x509: certificate is valid for 127.0.0.1, 192.168.1.83, not 192.168.1.153
    至于kubeconfig中的ca证书hosts是否包含ip,目前好像没影响,只要求对应的user是相应的system:node:192.168.1.153即可。
    cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kubelet-csr.json | cfssljson -bare kubelet
    cp kubelet-key.pem kubelet.pem /etc/kubernetes/ssl/     # 其他节点的话,就用scp即可
生成config文件kubectl config set-cluster kubernetes --certificate-authority=ca.pem --embed-certs=true --server=https://192.168.1.184:6443 --kubeconfig=./kubelet.kubeconfig
设置客户端认证参数kubectl config set-credentials system:node:192.168.1.184 --client-certificate=kubelet.pem --embed-certs=true --client-key=kubelet-key.pem --kubeconfig=./kubelet.kubeconfig
设置上下文参数kubectl config set-context default --cluster=kubernetes --user=system:node:192.168.1.184 --kubeconfig=./kubelet.kubeconfig
选择默认上下文kubectl config use-context default --kubeconfig=./kubelet.kubeconfig,使得kubelet可以访问集群资源,role为system:node
cp ./kubelet.kubeconfig /etc/kubernetes/
准备cni配置/etc/cni/net.d/10-default.conf        # 用于初始化master的时候kubelet变为ready用的,不然一直不ready,因为这个时候network插件还没部署。Unable to update cni config: no networks found in /etc/cni/net.d
准备kubelet yaml文件/var/lib/kubelet/config.yaml
准备kubelet.service文件/etc/systemd/system/kubelet.service
systemctl enable kubelet
systemctl daemon-reload && systemctl restart kubelet
准备kube-proxy文件/etc/systemd/system/kube-proxy.service
mkdir /var/lib/kube-proxy
systemctl enable kube-proxy
systemctl daemon-reload && systemctl restart kube-proxy
为节点打上相应的role名字kubectl label node 192.168.1.184 kubernetes.io/role=master --overwrite

扩容worker:

cp ca.pem ca-key.pem ca-config.json /etc/kubernetes/ssl/
准备/opt/cni/bin和/opt/kube/bin/
swapoff -a && sed -i '/swap/d' /etc/fstab && sysctl -w vm.swappiness=0
为该节点生成对应ip的kubelet-key.pem kubelet.pem(kubeconfig要重新生成,否则提示system:node:192.168.1.83cannot get resource,can only access node lease with the same name)
scp ca.pem ca-key.pem ca-config.json /etc/kubernetes/ssl/
准备文件/var/lib/kubelet/config.yaml和/etc/systemd/system/kube-proxy.service、/etc/systemd/system/kube-proxy.service
启动kubelet和kube-proxy

扩容master:

在worker的基础上
scp kube-proxy.kubeconfig kube-controller-manager.kubeconfig kube-scheduler.kubeconfig /etc/kubernetes/  # 每个master的可以不同。
关于etcd:
    原有的etcd高可用集群,一开始初始化的时候都配置好了集群的成员member,而且/var/lib/etcd/为空,master一个个顺序起来是可以的。
    扩容相当于在/var/lib/etcd/数据已存在,member已确定的情况下,再添加一个node,这是不允许的。
    对于扩容,由于member信息已经写好,需要通过命令行增加member才行
        ./etcdctl member list
        ./etcdctl member add etcd2 --peer-urls=https://192.168.1.162:2380       # 否则error validating peerURLs,member count is unequal
    然后etcd的service文件中需要配置--initial-cluster-state=existing               # 否则提示cluster ID mismatc,is starting a new election at term 173
        service文件中的name要修改对应
    不重新签发证书会提示rejected connection from "192.168.1.162:60004" (error "remote error: tls: bad certificate", ServerName "")
重新签发etcd证书,增加新的ip,        # 每个master的该证书可以不同,只保留自己ip。
准备/etc/systemd/system/etcd.service
启动etcd
重新签发apiserver证书-kubernetes,增加新的hosts ip来允许从哪个节点上可以访问它,复制到每个master上。该证书每个节点也可以不同。
cp kube-apiserver.service kube-controller-manager.service kube-scheduler.service /etc/systemd/system/        # kube-apiserver.service中的etcd server看情况需要增加
cp kubernetes-key.pem kubernetes.pem aggregator-proxy-key.pem aggregator-proxy.pem admin-key.pem admin.pem /etc/kubernetes/ssl/
cp kube-proxy.kubeconfig kube-controller-manager.kubeconfig kube-scheduler.kubeconfig /etc/kubernetes/
systemctl enable kube-apiserver kube-controller-manager kube-scheduler
systemctl start kube-apiserver kube-controller-manager kube-scheduler

问题:etcd不断在选择,is starting a new election at term 1109,原因有两个
    1.高可用的集群中,etcd的数量不够2个。
    2.etcd初始化由于各种原因加入失败,一直尝试加入。

关于kube-vip,可以在kuernetes的主要组件起来后,启用network后,再启用vip.yaml文件,pod起来后,即可搭建一个vip供访问。        
部署方式一:先启动kube-vip组件就提供一个虚拟ip,
    kubeadm部署的话,没有指定配置文件,但是传了kubeconfig,也可以获取到localPeer、remotePeers的信息。
    kubeadm init初始化的时候指定--control-plane-endpoint为vip,为所有控制平面节点设置共享端点。
    部署: 
        vip=192.168.1.35
        docker run --network host --rm plndr/kube-vip:0.2.1 manifest pod --interface ens3 --vip $vip --arp --leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml
        kubeadm init --kubernetes-version=v1.18.2 --control-plane-endpoint $vip --upload-certs
            初始化完成后,会给出其余master和worker join的命令
            这个时候节点还没ready,因为Unable to update cni config: no networks found in /etc/cni/net.d,部署weave后coredns和集群网络正常,node变为ready
        kubeadm join 192.168.1.35:6443 --token ixbsy4.ku7tjmmzgjp307io --discovery-token-ca-cert-hash sha256:4572e960edd6ea8 --control-plane --certificate-key 1ac26cc40c9f6d8a23eb414e361ed8d8a3d9fe1d6df2fc076f61dbc7425d7ab5
            其中的certificate-key可以通过kubeadm init phase upload-certs --upload-certs得出,token可以通过kubeadm token create或kubeadm token create --print-join-command,
            discovery-token-ca-cert-hash可以通过openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
            问题: 
                如果一开始join失败,后面再join会出现etcd等待第二个节点选举的问题,导致vip等待etcd一直起不来,导致apiserver(6443)用vip无法访问,同时也导致kubelet无法访问apiserver无法提供管理服务,
                将主节点重新部署后,一次性加入即可成功。如果尝试清空/var/lib/etcd会导致集群信息丢失。
                两个master节点的集群当一个master停机时也会这样。
        docker run --network host --rm plndr/kube-vip:0.2.1 manifest pod --interface ens3 --vip $vip --arp --leaderElection | sudo tee /etc/kubernetes/manifests/vip.yaml
            注意不同节点的网卡可能不同。
    高可用:
        一个非leader的node停机时,其他节点的etcd会尝试连接该节点,vip继续正常工作。
        两个非leader的node停机时,当前leader的vip由于etcd忙于选举,起不来,整个服务停止。开机后恢复正常。
        leader所在node停机时,vip组件切换leader,提示This node is starting with leadership of the cluster,Broadcasting ARP update
        delete一个node时,该node上还存在vip,vip不会漂移,因为kubelet服务没停,manifest还存在,直到kubeadm reset停掉container
        delete的节点需要处理etcd才能重新作为master加入。如果是worker则不用。如果是vip节点,还要ip ad del。
            ETCDCTL_API=3 ./etcdctl --endpoints=127.0.0.1:2379 member list --cacert /etc/kubernetes/pki/etcd/server.crt --cert /etc/kubernetes/pki/etcd/peer.crt --key /etc/kubernetes/pki/etcd/peer.key
            ETCDCTL_API=3 ./etcdctl --endpoints=127.0.0.1:2379 member remove xxx --cacert /etc/kubernetes/pki/etcd/server.crt --cert /etc/kubernetes/pki/etcd/peer.crt --key /etc/kubernetes/pki/etcd/peer.key

    目前来看主要体现为
        1.生成的kubeconfig文件里的server ip为vip。各个master的kubelet、apiserver等的ip还是自己的。
        2.apiserver使用的证书多加上了vip。

部署方式二:集群各个node起来后,通过kube-vip组件提供一个高可用的vip
    流程:
        1.准备配置文件config.yaml,里面配置了localPeer、remotePeers、loadBalancers等,用于选举leader和负载均衡
        2.cp config.yaml /etc/kube-vip/config.yaml
        3.准备yaml文件kube-vip.yaml,每个kube-vip需要指定运行的nodeName,不然会重复分配到一个节点上
        4.kubectl apply -f kube-vip.yaml
        5.同时,之前签发的kubeconfig要确保server地址为vip,才能高可用(否则当最初节点停机后,其他master不能调度)。
    注意: 
        kubeconfig要确保server地址为vip
    HA高可用原理:
        vip在多个master之间漂移,多个master的ip中之一。访问的是当前leader所在节点的业务服务,要求master之间都有有完整的业务系统。

        多个master启动kube-apiserver kube-controller-manager kube-scheduler的address填的都是自己的ip,但etcd的--etcd-servers填的是同一个,这样存储是相同的。
            也就是说,多master能实现同一个集群而不是单独的集群,是通过同一个etcd来实现的。

        worker的kubelet通过--kubeconfig里指定的server ip(vip)(set-cluster步骤生成)来向master通信请求,如表示worker自己处于ready状态,master可以向worker分配job。
            master和worker的kubelet.kubeconfig权限不一样(通过clusterrolebinding指定User或者Group,非ServiceAccount)。
            只要worker上的kubelet和kube-proxy起来后,kubectl get node就可以看到node了。这时候role还没分配而已。这时候可以分配job了。
            role没有实际的用途,taint还有一点。

        那么,如果vip组件在k8s之上的一层组件的话,可以在集群master都起来后再启动。

        master和worker节点的区别:
            worker节点上只运行了kubelet和kube-proxy。
            master除了运行了三个系统组件外,和worker的区别就是role的不同,导致了taint的不同。(可以将worker标记为master,但没有三个组件,会异常)

vip工作原理: 
    arp广播,配置localPeer、remotePeers、loadBalancers等,用于选举leader,至少两个节点(超过配置的半数)才能选举成功。单个节点也可以。
    需要startAsLeader: false      # 是否一开始就作为leader,多个实例时后面的实例需要为false。不然都广播,arp会收到多个包。

    实现方式:
        1.网卡双ip的方式
            ifconfig ens3:1 192.168.1.42/24或ip ad add 192.168.1.42/24 dev ens3
            手动增加可以体验arping收到多个来源
        2.网卡双ip+arp广播实时更新其他机器(除没有重启的旧leader)的arp表
            gratuitousARP: true(在2.2版本上为enableARP)
        3.BGP方式
        4.Packet方式

    扩容:
        一个kube-vip节点起来后,开始当leader
        新加入master后,需要先修改之前master的配置,增加ip,重启(否则新节点的投票会被拒绝), 然后新的master才能正常启动。

    测试:
        通过stop docker可以看到选举过程。
        1.至少需要两票,所以节点数量得为单数。
        2.leader负责与其他候选人通信,当失联时一直尝试,直到恢复。
        3.当leader失联时,两个节点进行选举,选出新的leader

    问题: 
        选举新的leader后,如果机器没有停电,只是关闭docker:
            1.除了剩余master所在的机器(永远实时更新),其他机器ip指向还是旧的(可以收到新的和旧的arp包,ssh登录使用旧的)。
                新增:可以通过ip route get 192.168.1.42查看可能的路由,如果是旧leader,双网卡,返回的是dev lo
            2.提供的6443还能访问旧的节点服务。
            3.使用arping/arp指令获取到的mac地址是新的,但ping、ssh等命令还是用旧的。
            4.tcpdump、nc等命令试了没效果,可以尝试arp -an和ip neigh查看arp缓存还是旧的mac地址,使用ip neigh flush清空后再ping可以获取新的mac地址。
                但一段时间后,机器的arp表又变回旧的mac地址,估计旧的一直在广播。
                新的机器如果从来没有获取过vip,可能优先选择旧的。
            5.原leader可以ip add show查看到vip绑定到网卡的inet上。执行删除ip ad del 192.168.1.42/24 dev ens3和清空arp后其他机器不再收到旧的arp包(leader切换会自动在旧机器执行这个)。
                原leader的双ip不会自动删除,需要重新上线后由pod自己删除。

特点:

1.采用Chrony进行时间同步
NTP 客户端的替代品,更快的同步只需要数分钟而非数小时时间,从而最大程度减少了时间和频率误差,对于并非全天 24 小时运行的虚拟计算机而言非常有用
2.Cfsslopenssl区别在于cfssl可以使用json格式,较方便。    

证书对比kubeadm:

admin-key.pem                    用于apiserver的--kubelet-client-key(kubelet TLS 客户端密钥文件)pki/apiserver-kubelet-client.key       
admin.pem                        用于apiserver的--kubelet-client-certificate                        pki/apiserver-kubelet-client.crt        
aggregator-proxy-key.pem        用于apiserver的--proxy-client-key-file(调用外部程序以处理请求)pki/front-proxy-client.key              
aggregator-proxy.pem            用于apiserver的--proxy-client-cert-file                            pki/front-proxy-client.crt              
ca-key.pem                        用于controller-manager的--cluster-signing-key-file             pki/ca.key
                                用于controller-manager的--service-account-private-key-file     pki/sa.key                                          
ca.pem                            用于controller-manager的--cluster-signing-cert-file                pki/ca.crt
                                用于controller-manager的--root-ca-file                         pki/ca.crt
                                /var/lib/kubelet/config.yaml                                    pki/ca.crt
                                用于etcd的--trusted-ca-file                                        pki/etcd/ca.crt
                                用于etcd的--peer-trusted-ca-file                               pki/etcd/ca.crt
                                用于apiserver的--client-ca-file                                    pki/ca.crt
                                用于apiserver的--etcd-cafile(用于保护 etcd 通信的 SSL 证书颁发机构文件)pki/etcd/ca.crt
                                用于apiserver的--kubelet-certificate-authority                 kubeadm中没有,证书颁发机构的证书文件的路径。
                                用于apiserver的--service-account-key-file                      pki/sa.pub
                                用于apiserver的--requestheader-client-ca-file(验证接入请求中客户端证书的根证书包)pki/front-proxy-ca.crt
etcd-key.pem                    用于etcd的--key-file                                           pki/etcd/server.key
                                用于etcd的--peer-key-file                                      pki/etcd/peer.key
etcd.pem                        用于etcd的--cert-file                                          pki/etcd/server.crt 
                                用于etcd的--peer-cert-file                                     pki/etcd/peer.crt   
kube-controller-manager-key.pem
kube-controller-manager.pem
kube-controller-manager.kubeconfig 用于controller-manager的--kubeconfig                            controller-manager.conf
kubelet-key.pem                    用于/var/lib/kubelet/config.yaml的tlsPrivateKeyFile                kubeadm中的kubelet没用上
kubelet.pem                        用于/var/lib/kubelet/config.yaml的tlsCertFile                  kubeadm中的kubelet没用上
kube-proxy-key.pem                
kube-proxy.pem
kube-proxy.kubeconfig            用于kube-proxy service的--kubeconfig                           kubeadm中的daemon资源的kube-proxy这个configmap
kubernetes-key.pem                用于apiserver的--etcd-keyfile(用于保护 etcd 通信的 SSL 密钥文件)pki/apiserver-etcd-client.key
                                用于apiserver的--tls-private-key-file(候选service-account-key-file)pki/apiserver.key
kubernetes.pem                    用于kube-apiserver的--tls-cert-file                                pki/apiserver.crt
                                用于apiserver的--etcd-certfile                                 pki/apiserver-etcd-client.crt
kube-scheduler-key.pem            
kube-scheduler.pem
kube-scheduler.kubeconfig        用于kube-scheduler的--kubeconfig                               scheduler.conf

卸载weave流程:

1.删除weave的k8s资源
2.rm -rf /etc/cni/net.d/10-weave.conflist

卸载集群:

1.清理etcd
systemctl stop etcd 
systemctl disable etcd 
rm -rf /var/lib/etcd /etc/etcd/ /etc/systemd/system/etcd.service
2.清理三个系统组件
systemctl stop kube-apiserver kube-controller-manager kube-scheduler
systemctl disable kube-apiserver kube-controller-manager kube-scheduler
rm -rf /var/run/kubernetes /etc/systemd/system/kube-apiserver.service /etc/systemd/system/kube-controller-manager.service /etc/systemd/system/kube-scheduler.service
3.清理kubelet和kube-proxy
systemctl stop kubelet kube-proxy
systemctl disable kubelet kube-proxy
mount | grep '/var/lib/kubelet'| awk '{print $3}'|xargs umount || exit 0
rm -rf /var/lib/kubelet/ /var/lib/kube-proxy/ /etc/systemd/system/kubelet.service /etc/systemd/system/kube-proxy.service /opt/kube/kube-system/ /etc/kubernetes/
umount目录:
    /var/run/docker/netns/default
    echo /var/lib/docker/overlay2/*/merged|xargs umount
    /var/lib/docker/overlay
    echo /var/lib/docker/containers/*/
mounts/shm|xargs umount
    echo /var/run/docker/netns/*|xargs umount
posted @ 2022-01-14 16:19  心平万物顺  阅读(1580)  评论(0编辑  收藏  举报