k8s-1.16高可用集群部署

机器要求

高可用集群一般用于生产环境,官方推荐至少需要3台master节点机器,4台node节点机器

Hostname IP Role
ucloud-bj-k8s-master-01 10.9.142.180 Master Node
ucloud-bj-k8s-node-01 10.9.165.222 Worker Node
ucloud-bj-k8s-node-02 10.9.127.58 Worker Node
ucloud-bj-K8s-node-03 10.9.57.4 Worker Node
ucloud-bj-K8s-node-04 10.9.174.192 Worker Node

安装准备

  1. 禁用Swap
    k8s为了使容器的调度更符合机器的实际资源情况,k8s建议关闭内存交换

    swapoff -a
    

    同时删除/etc/fstab中swap那条记录

    当然,如果你的机器资源确实不多,需要利用swap,那么你可以不关闭swap交换空间,通过如下参数告诉k8s开启swap

    kubelet --fail-swap-on=false ...
    
  2. 端口开放(生产环境)

Docker安装(可选)

由于k8s需要安装指定docker18.06版本,所以如果你的版本不对,可以先卸载重新安装

sudo apt-get remove docker docker-engine docker-ce docker.io

安装docker

# 从 Ubuntu 的存储库安装 Docker:
apt-get update
apt-get install -y docker.io

# 或者从 Docker 的 Ubuntu 或 Debian 镜像仓库中安装 Docker CE 18.06:

## 安装环境准备。
apt-get update && apt-get install apt-transport-https ca-certificates curl software-properties-common

## 下载 GPG 密钥。
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -

## 添加 docker apt 镜像仓库。
add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

## 安装 docker。
apt-get update && apt-get install docker-ce=18.06.0~ce~3-0~ubuntu

# 设置守护进程。
cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF

mkdir -p /etc/systemd/system/docker.service.d

# 重启 docker。
systemctl daemon-reload
systemctl restart docker

安装 kubelet,kubeadm,kubectl

添加阿里源密钥

curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add - 

国内源(阿里)

cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
EOF

安装

apt-get update
apt-get install -y kubelet=1.16.2-00 kubeadm=1.16.2-00 kubectl=1.16.2-00
apt-mark hold kubelet kubeadm kubectl
    

安装Master节点

kubeadm init --control-plane-endpoint "k8s-api.youxuetong.com:6443" --image-repository registry.aliyuncs.com/google_containers --pod-network-cidr=10.244.0.0/16 --upload-certs

如果安装完成,最后后输出如下内容

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

You can now join any number of control-plane nodes by copying certificate authorities
and service account keys on each node and then running the following as root:

  kubeadm join k8s-master:6443 --token vxszss.bboqeevhypvt0sxl \
    --discovery-token-ca-cert-hash sha256:56205646be3a53103e175d544dcd27cc82317c93042763cab20745334d8cb782 \
    --control-plane

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join k8s-master:6443 --token vxszss.bboqeevhypvt0sxl \
    --discovery-token-ca-cert-hash sha256:56205646be3a53103e175d544dcd27cc82317c93042763cab20745334d8cb782

部署CNI网络

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/2140ac876ef134e0ed5af15c65e414cf26827915/Documentation/kube-flannel.yml

接入其他Master节点

在其他master节点机器上执行

  kubeadm join k8s-master:6443 --token vxszss.bboqeevhypvt0sxl \
    --discovery-token-ca-cert-hash sha256:56205646be3a53103e175d544dcd27cc82317c93042763cab20745334d8cb782 \
    --control-plane

如果提示token失效,请利用下面的命令去第一个master节点重新生成token

kubeadm token create --print-join-command

接入其他Node节点

kubeadm join k8s-master:6443 --token vxszss.bboqeevhypvt0sxl \
    --discovery-token-ca-cert-hash sha256:56205646be3a53103e175d544dcd27cc82317c93042763cab20745334d8cb782

安装完成

查看各节点状态

ubuntu@ucloud-bj-k8s-master-01:~$ kubectl get nodes -o wide
NAME                      STATUS   ROLES    AGE   VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
ucloud-bj-k8s-master-01   Ready    master   26d   v1.16.2   10.9.142.180   <none>        Ubuntu 16.04.6 LTS   4.4.0-142-generic   docker://18.6.0
ucloud-bj-k8s-master-02   Ready    master   26d   v1.16.2   10.9.175.27    <none>        Ubuntu 16.04.6 LTS   4.4.0-142-generic   docker://18.6.0
ucloud-bj-k8s-master-03   Ready    master   26d   v1.16.2   10.9.91.143    <none>        Ubuntu 16.04.6 LTS   4.4.0-142-generic   docker://18.6.0
ucloud-bj-k8s-node-01     Ready    <none>   26d   v1.16.2   10.9.165.222   <none>        Ubuntu 16.04.6 LTS   4.4.0-142-generic   docker://18.6.0
ucloud-bj-k8s-node-02     Ready    <none>   26d   v1.16.2   10.9.127.58    <none>        Ubuntu 16.04.6 LTS   4.4.0-142-generic   docker://18.6.0
ucloud-bj-k8s-node-03     Ready    <none>   26d   v1.16.2   10.9.57.4      <none>        Ubuntu 16.04.6 LTS   4.4.0-142-generic   docker://18.6.0
ucloud-bj-k8s-node-04     Ready    <none>   26d   v1.16.2   10.9.174.192   <none>        Ubuntu 16.04.6 LTS   4.4.0-142-generic   docker://18.6.0
2020/01/10 posted in  Kubernetes

k8s-1.16单主节点集群部署

机器要求

单主集群一般用于开发环境,至少需要大于2台机器,一台作为主节点,其余的作为工作节点,机器间可以相互访问即可。

Hostname Ip Role
k8s-master 192.168.122.2 Master Node
k8s-node-01 192.168.122.101 Worker Node
k8s-node-02 192.168.122.102 Worker Node
K8s-node-03 192.168.122.103 Worker Node

需要注意:

如果你使用的是云服务器,服务器只有一块网卡,外网IP通过弹性IP绑定,请不要使用公网IP,使用内网网卡绑定的IP来通信。原因是,k8s只会监听网卡绑定IP的端口。

安装准备

  1. 禁用Swap
    k8s为了使容器的调度更符合机器的实际资源情况,k8s建议关闭内存交换

    swapoff -a
    

    同时删除/etc/fstab中swap那条记录

    当然,如果你的机器资源确实不多,需要利用swap,那么你可以不关闭swap交换空间,通过如下参数告诉k8s开启swap

    kubelet --fail-swap-on=false ...
    
  2. 关闭防火墙(开发环境)

    Ubuntu

    sudo ufw disable
    

    CentOS

    systemctl stop firewalld
    systemctl disable firewalld
    
  3. 禁用SELinux(开发环境)

    sudo apt install selinux-utils
    setenforce 0
    
  4. 确认mac地址以及product uuid唯一
    如果你的服务器是通过虚拟机克隆过来的,请确保这两项唯一

    ip link #检查mac地址
    sudo cat /sys/class/dmi/id/product_uuid ##检查uuid
    

Docker安装(可选)

由于k8s需要安装指定docker18.06版本,所以如果你的版本不对,可以先卸载重新安装

sudo apt-get remove docker docker-engine docker-ce docker.io

安装docker

# 从 Ubuntu 的存储库安装 Docker:
apt-get update
apt-get install -y docker.io

# 或者从 Docker 的 Ubuntu 或 Debian 镜像仓库中安装 Docker CE 18.06:

## 安装环境准备。
apt-get update && apt-get install apt-transport-https ca-certificates curl software-properties-common

## 下载 GPG 密钥。
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -

## 添加 docker apt 镜像仓库。
add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

## 安装 docker。
apt-get update && apt-get install docker-ce=18.06.0~ce~3-0~ubuntu

# 设置守护进程。
cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2"
}
EOF

mkdir -p /etc/systemd/system/docker.service.d

# 重启 docker。
systemctl daemon-reload
systemctl restart docker

开始安装 (切换到root身份)

  1. 安装相关工具

    apt-get update && apt-get install -y apt-transport-https curl
    
  2. 添加k8s软件源

    添加阿里源密钥

    curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add - 
    

    添加k8s阿里源

    cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
    deb https://mirrors.aliyun.com/kubernetes/apt/ kubernetes-xenial main
    EOF
  3. 安装 kubelet,kubeadm,kubectl

    apt-get update
    apt-get install -y kubelet kubeadm kubectl
    apt-mark hold kubelet kubeadm kubectl

    非root用户需要加上sudo

部署master

初始化master节点

kubeadm init --apiserver-advertise-address=192.168.122.2 --image-repository registry.aliyuncs.com/google_containers --pod-network-cidr=10.244.0.0/16

参数解释:

  • --apiserver-advertise-address: k8s 中的主要服务apiserver的部署地址,填自己的管理节点 ip
  • --image-repository: 拉取的 docker 镜像源,因为初始化的时候kubeadm会去拉 k8s 的很多组件来进行部署,所以需要指定国内镜像源,下不然会拉取不到镜像。
  • --pod-network-cidr: 这个是 k8s 采用的节点网络,因为我们将要使用flannel作为 k8s 的网络,所以这里填10.244.0.0/16就好
  • --kubernetes-version: 这个是用来指定你要部署的 k8s 版本的,一般不用填,不过如果初始化过程中出现了因为版本不对导致的安装错误的话,可以用这个参数手动指定。
  • --gnore-preflight-errors: 忽略初始化时遇到的错误,比如说我想忽略 cpu 数量不够 2 核引起的错误,就可以用--ignore-preflight-errors=CpuNum。错误名称在初始化错误时会给出来。

执行上面的命令,等待安装完成,知道出现下面的文字表示安装成功

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.122.2:6443 --token 1gyku3.72jgt8prrp2fdhhx \
    --discovery-token-ca-cert-hash sha256:9c5bf462c308be3a69b6766e71f367e48e222c4ee019c4ec438e02e089ab4e12

复制保存kubeadm join那行的文字,后面添加节点需要使用到,注意,token默认是24小时会过期,可以在master上利用如下命令查看token是否有效

kubeadm token list

如果没有有效token,可以重新创建一个

kubeadm token create

初始化kubectl工具

按照kubeadm的指示操作就行,依次执行如下命令,用普通用户的账号

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

如果你想在root用户下使用

export KUBECONFIG=/etc/kubernetes/admin.conf

部署flannel (Pod Network Adds-on)

k8s依赖于第三的节点网络,以便各pod节点之间可以相互通信

kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/2140ac876ef134e0ed5af15c65e414cf26827915/Documentation/kube-flannel.yml

如果遇到timeout错误,请使用代理

输出以下内容代表安装完成

clusterrole.rbac.authorization.k8s.io/flannel created
clusterrolebinding.rbac.authorization.k8s.io/flannel created
serviceaccount/flannel created
configmap/kube-flannel-cfg created
daemonset.extensions/kube-flannel-ds-amd64 created
daemonset.extensions/kube-flannel-ds-arm64 created
daemonset.extensions/kube-flannel-ds-arm created
daemonset.extensions/kube-flannel-ds-ppc64le created
daemonset.extensions/kube-flannel-ds-s390x created

添加node节点

按照最前面的部署安装好k8s相关程序

kubeadm join 192.168.122.2:6443 --token 1gyku3.72jgt8prrp2fdhhx \
    --discovery-token-ca-cert-hash sha256:9c5bf462c308be3a69b6766e71f367e48e222c4ee019c4ec438e02e089ab4e12

如果join命令忘记了复制,可以去master节点上执行

kubeadm token create --print-join-command

详细安装日志

可以通过在命令后面增加--v=5来查看详细安装日志,例如

kubeadm join 192.168.122.2:6443 --token 1gyku3.72jgt8prrp2fdhhx \
    --discovery-token-ca-cert-hash sha256:9c5bf462c308be3a69b6766e71f367e48e222c4ee019c4ec438e02e089ab4e12 --v=5

安装完成

主节点执行kubectl get nodes -o wide,检查各节点是否为Ready状态

ubuntu@k8s-master:~$ kubectl get nodes -o wide
NAME          STATUS   ROLES    AGE   VERSION   INTERNAL-IP       EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
k8s-master    Ready    master   23d   v1.16.2   192.168.122.2     <none>        Ubuntu 16.04.6 LTS   4.4.0-142-generic   docker://18.6.0
k8s-node-01   Ready    <none>   23d   v1.16.2   192.168.122.101   <none>        Ubuntu 16.04.6 LTS   4.4.0-142-generic   docker://18.6.0
k8s-node-02   Ready    <none>   23d   v1.16.2   192.168.122.102   <none>        Ubuntu 16.04.6 LTS   4.4.0-142-generic   docker://18.6.0
2020/01/10 posted in  Kubernetes

Kubernets特性介绍

Kubernetes 源于希腊语,意为 “舵手” 或 “飞行员”。它是Google开源的一个容器编排引擎,它支持自动化部署、大规模可伸缩、应用容器化管理,由于Kubernetes单词中,k和s之间的单词数量为8个,所以也简称k8s。

系统架构

单主集群

单主集群,是集群内只包含一个Control Panel节点的集群,一般用作开发环境,下图是单主集群的结构。

由于主节点只有一个,且work节点无法再主节点宕机后选举产生新的主节点,所有单主集群不适用与产品环境。

高可用集群

高可用集群,是至少包含三个Control Panel节点的集群,Work节点不再直接与某一台主节点的api-server联系,而是通过负载均衡均匀分不到master节点,同时由于etcd节点可以使用外部集群替代,高可用集群又分为内部etcd以及外部etcd集群两种。

内部etcd节点集群

外部etcd节点集群

Kubernets的优势

简化应用程序部署和维护工作,同时最大化利用硬件资源

自动修复

k8s 会自动重新启动失败的容器、替换容器、杀死不响应用户定义的运行状况检查的容器,并且这些都是在用户无感知的情况下进行的(副本数量需要大于1且有正常运行的容器)。

要想介绍k8s的自动修复,必须要介绍存活探针,k8s正是利用存活探针来检查容器是否还在运行,如果探测失败,k8s将自动重启该容器。

k8s有三种探针机制:

  1. HTTP GET: 针对容器的IP地址,端口以及路径,执行HTTP GET请求,如果收到的返回状态码为2xx或者3xx,则认为探测成功
  2. TCP: 针对Socket通信进行探测,尝试与指定端口建立TCP连接,如果连接成功则探测成功。
  3. Exec: 在容器内执行指定的命令,并检查命令的退出状态码,如果状态码为0,则探测成功。

我们先声明一个拥有两个副本的pod,创建deployment.yaml文件,写入下面的内容

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kubia
spec:
  replicas: 2
  selector:
    app: kubia
  template:
    metadata:
      name: kubia
      labels:
        app: kubia
    spec:
      containers:
        - name: kubia
          image: luksa/kubia
          livenessProbe:
              httpGet:
                path: /
                port: 8080
          ports:
            - containerPort: 8080

然后利用kubectl创建pod

kubectl create -f deployment.yaml -n default

查看pod状态

ubuntu@k8s-master:~$ kubectl get pods -n default
NAME          READY   STATUS    RESTARTS   AGE
kubia-dvdkl   1/1     Running   0          4m55s
kubia-g7z9g   1/1     Running   0          4m55s

等两个pod都完全运行起来之后,我们先模拟第一种情况,程序异常退出,我们删除掉其中一个Pod

ubuntu@k8s-master:~$ kubectl delete pod kubia-g7z9g -n default
pod "kubia-g7z9g" deleted
ubuntu@k8s-master:~$ kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
kubia-dvdkl   1/1     Running   0          7m43s
kubia-jtq6c   1/1     Running   0          39s

可以看到,很快另外一个应用以及重新运行起来了。

再来看另外一种情况,节点故障,我们关闭其中一台node节点

ubuntu@k8s-master:~$ kubectl get nodes
NAME          STATUS     ROLES    AGE     VERSION
k8s-master    Ready      master   26d     v1.16.2
k8s-node-01   Ready      <none>   26d     v1.16.2
k8s-node-02   Ready      <none>   26d     v1.16.2
k8s-node-03   Ready      <none>   26d     v1.16.2
k8s-node-04   Ready      <none>   18d     v1.16.2
k8s-node-05   Ready      <none>   16d     v1.16.2
k8s-node-06   Ready      <none>   14d     v1.16.2
k8s-node-07   Ready      <none>   4d20h   v1.16.2
k8s-node-08   NotReady   <none>   4d19h   v1.16.2

等待几分钟后,查看Pods

ubuntu@k8s-master:~$ kubectl get pods -n default -o wide
NAME          READY   STATUS        RESTARTS   AGE     IP            NODE          NOMINATED NODE   READINESS GATES
kubia-cpmbh   0/1     Pending       0          0s      <none>        k8s-node-06   <none>           <none>
kubia-dvdkl   1/1     Terminating   1          4d19h   10.244.8.44   k8s-node-08   <none>           <none>
kubia-jtq6c   1/1     Running       0          4d19h   10.244.7.5    k8s-node-07   <none>           <none>

针对节点故障,k8s并不会把出问题的节点上的所有Pod都迁移到别的Pod上,而是创建新的Pod,原来的Pod仍然保留,只是状态不再是Ready,如果节点恢复,原来的Pod状态也会恢复。

服务发现

我们先为kubia应用创建一个服务,创建service.yaml,写入下面的内容

kind: apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  selector:
    app: kubia
  ports:
  - port: 80
    targetPort: 8080

执行kubectl create -f service.yaml -n default创建服务

ubuntu@k8s-master:~/k8s-dev$ kubectl create -f kubia/service.yaml -n default
service/kubia created

查看service状态

ubuntu@k8s-master:~/k8s-dev$ kubectl get svc -n default
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP   26d
kubia        ClusterIP   10.107.59.19   <none>        80/TCP    27s

k8s的服务发现分为两种,集群内部访问和集群外部访问

集群内部

可以通过内置的DNS用服务名的方式访问集群内部的应用,同时也能利用环境变量获取开放的端口。

通过环境变量访问服务

当pod创建时,k8s会把当前命名空间内已存在的服务已环境变量的方式导入到pod当中,所以只要你的pod晚于service的创建,pod里的进程就可以根据环境变量获得服务的IP和端口号。
我们先查看pod早于service创建的情况

ubuntu@k8s-master:~/k8s-dev$ kubectl exec kubia-8fffd4bff-k4tk4 env -n default
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=kubia-8fffd4bff-k4tk4
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
NPM_CONFIG_LOGLEVEL=info
NODE_VERSION=7.9.0
YARN_VERSION=0.22.0
HOME=/root

然后我们删除pod,让他自动修复

kubectl delete pod --all -n default

查看新的pod

ubuntu@k8s-master:~/k8s-dev$ kubectl get pods -n default
NAME                    READY   STATUS    RESTARTS   AGE
kubia-8fffd4bff-622rl   1/1     Running   0          44s
kubia-8fffd4bff-6h64s   1/1     Running   0          44s

查看新pod的环境变量

ubuntu@k8s-master:~/k8s-dev$ kubectl exec kubia-8fffd4bff-622rl env -n default
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=kubia-8fffd4bff-622rl
KUBIA_PORT_80_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_PORT=443
KUBIA_SERVICE_PORT=80
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
KUBIA_SERVICE_HOST=10.107.59.19
KUBIA_PORT_80_TCP_PORT=80
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBIA_PORT=tcp://10.107.59.19:80
KUBIA_PORT_80_TCP=tcp://10.107.59.19:80
KUBIA_PORT_80_TCP_ADDR=10.107.59.19
KUBERNETES_SERVICE_HOST=10.96.0.1
KUBERNETES_SERVICE_PORT_HTTPS=443
NPM_CONFIG_LOGLEVEL=info
NODE_VERSION=7.9.0
YARN_VERSION=0.22.0
HOME=/root

对比两种情况,可以发现,KUBIA_SERVICE_HOSTKUBIA_SERVICE_PORT已经存在于环境变量当中了。

通过DNS访问服务

在k8s内部,借助CoreDNS,一旦一个服务创建好,我们可以用hostname.namespace.svc.cluster.local这个域名来获取到服务的IP地址,如果应用和服务同一个集群内部,甚至在同一个命名空间下,我就可以直接用hostname访问该服务
利用service名称访问服务

ubuntu@k8s-master:~/k8s-dev$ kubectl exec kubia-8fffd4bff-622rl curl http://kubia -n default
You've hit kubia-8fffd4bff-622rl
kubectl exec kubia-8fffd4bff-622rl curl http://kubia.default.svc.cluster.local -n default
You've hit kubia-8fffd4bff-6h64s

那么问题来了,利用DNS的方式访问服务确实很方便,但是DNS只能解决IP,针对端口问题怎么办?
针对这种情况我们的处理办法是固定端口,应为在k8s内部大部分应用独享一个IP的所有端口,所以不存在端口冲突的问题,我们可以针对不同的协议约定一个统一的端口,这样应用就不需要知道具体应用的端口了。

常用协议默认端口:
http: 80
https: 443
mysql: 3306
redis: 6379
gRPC: 9000

集群外部

k8s提供了NodePort,LoadBlancer,Ingres三种服务暴露的方式,应用于各种需要对外暴露服务的场景。
其中LoadBlancer属于云服务商特有的功能,如果你是私有集群,大概率是用不了这个功能了。

NodePort

NodePort的原理时,在所有Node节点上监听一个端口(所有node节点端口相同),并将传入的数据转发到对应的服务上。

我们修改之前的kubia应用的service.yaml

kind: apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  type: NodePort
  selector:
    app: kubia
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 20000

这次我们指定type类型为NodePort,同时注明nodePort的端口号为20000
我们更新看看效果

ubuntu@k8s-master:~/k8s-dev$ kubectl delete svc kubia -n default
service "kubia" deleted
ubuntu@k8s-master:~/k8s-dev$ kubectl create -f kubia/service-nodeport.yaml -n default
service/kubia created

查看新的service

ubuntu@k8s-master:~/k8s-dev$ kubectl get svc -n default
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP        26d
kubia        NodePort    10.111.0.106   <none>        80:30123/TCP   38s

对比之前的service,新的kubia服务多了一个30123端口,我们可以通过集群任意node节点的ip地址访问这个端口

ubuntu@k8s-master:~/k8s-dev$ curl http://127.0.0.1:30123
You've hit kubia-8fffd4bff-622rl
Ingress

ingress功能在k8s默认集群里没有提供,需要手动安装开启。ingress可以让应用在http层暴露给外部,通过配置不同的host来指向不同的服务

我们先为kubia这个应用创建一个ingress资源ingress.yaml

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: kubia
spec:
  rules:
  - host: kubia.dev.youxuetong.com
    http:
      paths:
        - path: /
          backend: 
            serviceName: kubia
            servicePort: 80

创建ingress资源并查看

ubuntu@k8s-master:~$ kubectl create -f k8s-dev/kubia/ingress.yaml -n default
ingress.networking.k8s.io/kubia created
ubuntu@k8s-master:~$ kubectl get ingress -n default
NAME    HOSTS                      ADDRESS   PORTS   AGE
kubia   kubia.dev.youxuetong.com             80      13s

我们试试通过域名访问这个服务

➜  ~ curl http://kubia.dev.youxuetong.com
You've hit kubia-8fffd4bff-622rl

负载均衡

k8s可以将网络流量随机分发(按照一定规则,在最新的1.17中,会选择一个最短路由的pod节点)到pod节点上。

我们可以看到每次访问同一服务,都可能会落到不同的pod节点上

➜  ~ curl http://kubia.dev.youxuetong.com
You've hit kubia-8fffd4bff-622rl
➜  ~ curl http://kubia.dev.youxuetong.com
You've hit kubia-8fffd4bff-622rl
➜  ~ curl http://kubia.dev.youxuetong.com
You've hit kubia-8fffd4bff-622rl
➜  ~ curl http://kubia.dev.youxuetong.com
You've hit kubia-8fffd4bff-6h64s
➜  ~ curl http://kubia.dev.youxuetong.com
You've hit kubia-8fffd4bff-6h64s
➜  ~ curl http://kubia.dev.youxuetong.com
You've hit kubia-8fffd4bff-6h64s

如果有些特殊应用,希望同一个用户的访问能指向同一个pod,比如处理socket长连接的应用,可以通过更改service的会话亲和性来达到效果

apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  sessionAffinity: ClientIP
  selector:
    app: kubia
  ports:
  - port: 80
    targetPort: 8080

重新创建service后我们来看看效果

ubuntu@k8s-master:~/k8s-dev$ kubectl delete svc kubia -n default
service "kubia" deleted
ubuntu@k8s-master:~/k8s-dev$ kubectl create -f kubia/service-session.yaml -n default
service/kubia created

利用curl访问

ubuntu@k8s-master:~$ curl http://127.0.0.1:30123
You've hit kubia-8fffd4bff-6h64s
ubuntu@k8s-master:~$ curl http://127.0.0.1:30123
You've hit kubia-8fffd4bff-6h64s
ubuntu@k8s-master:~$ curl http://127.0.0.1:30123
You've hit kubia-8fffd4bff-6h64s
ubuntu@k8s-master:~$ curl http://127.0.0.1:30123
You've hit kubia-8fffd4bff-6h64s
ubuntu@k8s-master:~$ curl http://127.0.0.1:30123
You've hit kubia-8fffd4bff-6h64s
ubuntu@k8s-master:~$ curl http://127.0.0.1:30123
You've hit kubia-8fffd4bff-6h64s    

配置文件

k8s支持将一些敏感信息以及相关应用的配置文件单独存放,做到和应用无关。

创建ConfigMap,configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: kubia
  labels:
    app: kubia
   
data:
  config.json: |-
    {
      "service":{
        "host":"http://kubia.dev.youxuetong.com",
        "ip":"10.9.22.1",
        "port":80
      }    
    }
  config.yaml: |-
    service:
      host: "http://kubia.dev.youxuetong.com"
      ip: "10.9.22.1"
      port: 80

修改deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kubia
spec:
  replicas: 2
  selector:
    matchLabels:
      app: kubia
  template:
    metadata:
      name: kubia
      labels:
        app: kubia
    spec:
      volumes:
        - name: config
          configMap:
            name: kubia
      containers:
        - name: kubia
          image: luksa/kubia
          livenessProbe:
              httpGet:
                path: /
                port: 8080
          volumeMounts:
          - name: config
            mountPath: /opt/config
            readOnly: true
          ports:
            - containerPort: 8080

生成configmap,删除之前的deployment,创建新的

ubuntu@k8s-master:~/k8s-dev$ kubectl create -f kubia/configmap.yaml -n default
configmap/kubia created
ubuntu@k8s-master:~/k8s-dev$ kubectl delete deployment kubia -n default
deployment.apps/kubia deleted
ubuntu@k8s-master:~/k8s-dev$ kubectl create -f kubia/deployment-config.yaml -n default
deployment.apps/kubia created

我们进入pod中查看配置文件是否挂载成功

ubuntu@k8s-master:~/k8s-dev$ kubectl exec kubia-65cbb6d475-c5pqk ls /opt/config -n default
config.json
config.yaml
ubuntu@k8s-master:~/k8s-dev$ kubectl exec kubia-65cbb6d475-c5pqk cat /opt/config/config.json -n default
{
  "service":{
    "host":"http://kubia.dev.youxuetong.com",
    "ip":"10.9.22.1",
    "port":80
  }
}
ubuntu@k8s-master:~/k8s-dev$ kubectl exec kubia-65cbb6d475-c5pqk cat /opt/config/config.yaml -n default
service:
  host: "http://kubia.dev.youxuetong.com"
  ip: "10.9.22.1"
  port: 80

密钥管理

密钥管理和配置文件类似,只是密钥当中存储的的是一些敏感信息而已。
我们以https证书举例,当我们在k8s当中,想给我们的域名绑上https证书的时候
先创建证书secret,需要实现准备好证书的key和证书文件

ubuntu@k8s-master:~/k8s-dev/ssl-dev.youxuetong.com$ kubectl create secret tls dev.youxuetong.com --cert=server.crt --key=server.key -n default
secret/dev.youxuetong.com created

这时我们如果想给之前通过ingress暴露的域名http://kubia.dev.youxuetong.com加上https证书,只需要修改ingress.yaml

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: kubia
spec:
  rules:
  - host: kubia.dev.youxuetong.com
    http:
      paths:
        - path: /
          backend: 
            serviceName: kubia
            servicePort: 80
  tls:
  - hosts:
    - kubia.dev.youxuetong.com
    secretName: dev.youxuetong.com

增加tls字段,为kubia.dev.youxuetong.com 绑上之前创建好的secret
我们利用curl查看https证书有没有生效

ubuntu@k8s-master:~/k8s-dev$ curl -k -v https://kubia.dev.youxuetong.com/
*   Trying 125.46.60.5...
* Connected to kubia.dev.youxuetong.com (125.46.60.5) port 443 (#0)
* found 149 certificates in /etc/ssl/certs/ca-certificates.crt
* found 596 certificates in /etc/ssl/certs
* ALPN, offering http/1.1
* SSL connection using TLS1.2 / ECDHE_RSA_AES_256_GCM_SHA384
*    server certificate verification SKIPPED
*    server certificate status verification SKIPPED
*    common name: *.dev.youxuetong.com (matched)
*    server certificate expiration date OK
*    server certificate activation date OK
*    certificate public key: RSA
*    certificate version: #3
*    subject: C=CN,ST=HeNan,L=ZhengZhou,O=JiangShan Technology Co.Ltd,OU=JiangShan Technology Co.Ltd,CN=*.dev.youxuetong.com,EMAIL=yxt@youxuetong.com
*    start date: Fri, 03 Jan 2020 02:27:09 GMT
*    expire date: Mon, 17 May 2021 02:27:09 GMT
*    issuer: C=CN,ST=henan,L=zhengzhou,O=Jiangshan Co.Ltd,OU=Jiangshan Co.Ltd,CN=Jiangshan Co.Ltd,EMAIL=yxt@youxuetong.com
*    compression: NULL
* ALPN, server accepted to use http/1.1
> GET / HTTP/1.1
> Host: kubia.dev.youxuetong.com
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: openresty/1.15.8.2
< Date: Tue, 14 Jan 2020 06:26:32 GMT
< Transfer-Encoding: chunked
< Connection: keep-alive
< Strict-Transport-Security: max-age=15724800; includeSubDomains
<
You've hit kubia-65cbb6d475-c5pqk

统一存储

k8s允许您自由选择的适合自己存储系统,无论是本地存储、远程目录共享还是云服务商提供的网络磁盘,并提供统一的分配和挂载方案。
存储分为静态存储和动态存储

静态存储

静态存储需要事先在node上创建目录,分配空间,然后将目录挂载到pod上,和docker的目录挂载原理一样。这样的缺点就是每创建一个应用之前还需要手动创建目录,同时这样生成的pod的流动性就很差了,所以大部分情况下我们不会使用。

动态存储

无需实现绑定,应用程序只需创建一个存储卷声明,声明所需磁盘空间大小和类型,即可自动完成创建和绑定。
我们先创建一个持久卷声明pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: kubia-pvc
  labels:
    app: kubia
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

然后在deployment上绑定已经创建的pvc

apiVersion: apps/v1
kind: Deployment
metadata:
  name: kubia
spec:
  replicas: 2
  selector:
    matchLabels:
      app: kubia
  template:
    metadata:
      name: kubia
      labels:
        app: kubia
    spec:
      volumes:
        - name: kubia-data
          persistentVolumeClaim:
            claimName: kubia-pvc
      containers:
        - name: kubia
          image: luksa/kubia
          livenessProbe:
              httpGet:
                path: /
                port: 8080
          volumeMounts:
          - name: kubia-data
            mountPath: /data
          ports:
            - containerPort: 8080

重新创建各项资源

ubuntu@k8s-master:~/k8s-dev$ kubectl create -f kubia/pvc.yaml -n default
persistentvolumeclaim/kubia-pvc created
ubuntu@k8s-master:~/k8s-dev$ kubectl get pvc -n default
NAME        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
kubia-pvc   Bound    pvc-bb91d0ac-5076-41ba-b1fa-beb26473a0dc   10Gi       RWO            nfs-client     29s
ubuntu@k8s-master:~/k8s-dev$ kubectl delete deployment kubia -n default
deployment.apps "kubia" deleted
ubuntu@k8s-master:~/k8s-dev$ kubectl create -f kubia/deployment-pvc.yaml -n default
deployment.apps/kubia created

我们进入目录查看目录是否挂载成功,并创建一个文件

ubuntu@k8s-master:~/k8s-dev$ kubectl exec kubia-5bb69778fc-n2v6k touch /data/readme.md -n default

去NFS服务器查看文件是否成功创建

ubuntu@K8S-NFS:/data$ cd default-kubia-pvc-pvc-bb91d0ac-5076-41ba-b1fa-beb26473a0dc/
ubuntu@K8S-NFS:/data/default-kubia-pvc-pvc-bb91d0ac-5076-41ba-b1fa-beb26473a0dc$ ll
total 8
drwxrwxrwx  2 root root 4096 Jan 14 00:54 ./
drwxrwxrwx 21 root root 4096 Jan 14 00:51 ../
-rw-r--r--  1 root root    0 Jan 14 00:54 readme.md

统一日志

利用EFK(elasticsearch,fluentd,kibaba)很容易做到对这个集群的日志跟踪。

在k8s里,Fluentd会被安装在每个Node节点上,同时会挂载当前机器的/var/lib/docker/containers目录,由于docker所有的标准输出都会在该目录下记录日志,所以Fluentd可以很容易的做到将整个集群上所允许的应用的日志统一发送到后端。

统一监控

利用Metric-Server可以获取pod集群的资源占用情况的数据,在加上Prometheus和Grafana很容搭建一套集群的监控报警系统。

滚动升级&回滚

k8s提供逐步更新应用程序的能力,并提供不同的升级策略,让用户无感知情况下升级或者回滚应用程序。

自动伸缩

k8s不仅提供手动的应用程序扩容机制,同时还可以通过监视应用程序的CPU使用率或其他度量增长时自动对应用程序进行扩容,已应用短期的高并发请求。

2020/01/02 posted in  Kubernetes

K8S日志系统EFK

elasticsearch

helm install elasticsearch stable/elasticsearch -n share

fluentd

helm repo add kiwigrid https://kiwigrid.github.io
helm repo update
helm install fluentd  kiwigrid/fluentd-elasticsearch --set elasticsearch.bufferChunkLimit="20M",elasticsearch.bufferQueueLimit=20 -n share

bufferChunkLimit 一次发送数据的最大限制
bufferQueueLimit 待发送数据的最大数量限制

bufferChunkLimit * bufferQueueLimit 应小于PC内存

kibana

helm install kibana stable/kibana --set ingress.enabled=true,ingress.hosts[0]=kibana.dev.youxuetong.com -n share

需要手动修改kibana的configmap,修改其中的elasticsearch.hosts

data:
  kibana.yml: |
    elasticsearch.hosts: http://elasticsearch-client:9200
    server.host: "0"
    server.name: kibana

删除正在运行的kibana的pod

kubectl delete pod kibana-557d4dc6b9-7dx5j -n share
2019/12/27 posted in  Kubernetes

WebDashboard UI部署

下载官方文件

wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta4/aio/deploy/recommended.yaml

修改文件,去除自建的secret

#---
## 由于证书问题,只能firefox浏览器才能打开,通过修改证书的方式,使得所有浏览器都能打开
#apiVersion: v1
#kind: Secret
#metadata:
#  labels:
#    k8s-app: kubernetes-dashboard
#  name: kubernetes-dashboard-certs  #生成证书会用到该名字
#  namespace: kubernetes-dashboard  #生成证书使用该命名空间
#type: Opaque

修改service为NodePort方式

kind: Service
apiVersion: v1
metadata:
  labels:
    k8s-app: kubernetes-dashboard
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
spec:
  type: NodePort
  ports:
    - port: 443
      targetPort: 8443
      nodePort: 32000
  selector:
    k8s-app: kubernetes-dashboard

创建自签名证书

# 创建目录使用证书
mkdir key && cd key
# 查看是否存在namespace为kubernetes-dashboard
kubectl get namespaces
# 不存在namespace为创建kubernetes-dashboard创建namespace
kubectl create namespace kubernetes-dashboard
# 生成 key
openssl genrsa -out dashboard.key 2048
# 生成证书请求
openssl req -days 36000   -new -out dashboard.csr    -key dashboard.key   -subj '/CN=**192.168.100.10**'
# 生成自签证书
openssl x509 -req -in dashboard.csr -signkey dashboard.key -out dashboard.crt
# 目录结构
[root@k8smaster key]# ll
total 12
-rw-r--r-- 1 root root 1001 Oct 23 22:21 dashboard.crt
-rw-r--r-- 1 root root  903 Oct 23 22:20 dashboard.csr
-rw-r--r-- 1 root root 1679 Oct 23 22:20 dashboard.key
# 使用自签证书创建secret
kubectl create secret generic kubernetes-dashboard-certs     --from-file=dashboard.key     --from-file=dashboard.crt      -n kubernetes-dashboard

应用配置文件

kubectl create -f recommend.yaml

添加管理员并绑定管理员权限

# 创建sa
kubectl create serviceaccount dashboard-admin -n kubernetes-dashboard
# 绑定集群管理员
kubectl create clusterrolebinding  dashboard-cluster-admin --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:dashboard-admin

获取登录token

kubectl describe secrets  $(kubectl  get secrets -n kubernetes-dashboard | awk  '/dashboard-admin-token/{print $1}' ) -n kubernetes-dashboard |sed -n '/token:.*/p'

浏览器访问https://IP:32000
如果Chrome浏览器仍然显示非安全连接,且详细信息中没有继续前往按钮,请用safari打开该连接,点击详细信息中的继续前往,按照系统只是操作,最后发现该自签名证书会被添加到钥匙串中,之后在用chrome浏览器打卡就不会出现无法访问的情况了。

2019/12/26 posted in  Kubernetes