发展历史
Infrastructure as a Service 阿里云
platform as a Service 新浪云
Software as Service Office365
资源管理器
- Apache MESOS 分布式的资源管理框架 2019-05 最大使用厂商Twitter不在使用,改为Kubernetes
- Docker Swarm 与Docker绑定 2019-07 阿里云宣布Docker Swarm 从阿里选择列表里剔除
- Kubernetes Google 2014年创建管理的,是Google 10多年大规模容器管理技术Borg的开源版本
Kerbernetes是什么
Kubernetes是容器集群管理系统,是一个开源的平台,可以实现容器集群的自动化部署、自动扩缩容、维护等功能。
Kubernetes特点
- 可移植: 支持公有云,私有云,混合云,多重云(multi-cloud)
- 可扩展: 模块化, 插件化, 可挂载, 可组合
- 自动化: 自动部署,自动重启,自动复制,自动伸缩/扩展
- 轻量级: 消耗资源小
- 负载均衡: IPVS
Kubernetes组件说明
Borg架构
k8s架构
Master组件
- etcd
etcd的官方将它定位 成一个可信赖的分布式键值存储服务. etcd是Kubernetes提供默认的存储系统,它能够为整个分布式集群存储一些关键数据,协助分布式集群的正常运转.
- scheduler
负责资源的调度,监视新创建没有分配到Node的Pod,为Pod选择一个Node. - controller manager
负责维护集群的状态,比如故障检测、自动扩展、滚动更新等. - api server
提供了资源操作的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制.
Node组件
- kubelet
负责维护容器的生命周期,同时也负责Volume(CVI)和网络(CNI)的管理. - kube-proxy
负责为Service提供cluster内部的服务发现和负载均衡. - **Container **
runtime负责镜像管理以及Pod和容器的真正运行(CRI).
其它插件说明
- DNS
负责为整个集群提供DNS服务. - Dashboard
提供GUI. - Ingress Controller
为服务提供外网入口. - Federation
提供跨可用区的集群.
搭建k8s集群
前置知识点
目前生产部署Kubernetes集群主要有两种方式:
- kubeadm
Kubeadm是一个k8s部署工具,提供kubeadm init
和kubeadm join
,用于快速部署Kubernetes集群.
官方地址: https://kubernetes.io/docs/reference/setup-tools/kubeadm/ - 二进制包
从github上下载发行版的二进制包,手动部署每个组件,组成Kubernetes集群.
Kubeadm降低部署门槛,但屏蔽了很多细节,遇到问题很难排查.如果想更容易可控,推荐使用二进制包部署Kubernetes集群,虽然手动部署麻烦点,期间可以学习很多工作原理,也利于后期维护.
kubeadm 部署方式介绍
kubeadm是官方社区推出的一款用于快速部署Kubernetes集群的工具,这个工具能够通过两条指令完成一个Kubernetes集群的部署.
- 创建一个Master节点
kubeadm init
- 将Node节点加入到当前集群中
kubeadm join <Master节点的IP和端口>
安装要求
在开始之前,部署Kubernetes集群集群需要满足以下几个条件:
- 一台或多台机器, 操作系统Centos7.x
- 硬件配置:2核4G或更高配置
- 集群中所有机器之间网络互通
- 可以访问外网,需要拉去镜像
- 禁止swap分区
环境准备
- 在所有节点上安装Docker 和 Kubeadm
- 部署Kubernetes Master
- 部署容器网络插件
- 部署Kubernetes Node, 将节点加入Kubernetes集群中
- 部署Dashboard Web页面,可视化查看Kubernetes资源
关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
关闭selinux
sed -i 's/enforcing/disabled/' /etc/selinux/config # 永久
setenforce 0 # 临时
关闭swap
sudo sed -ri 's/.*swap.*/#&/' /etc/fstab # 永久
sudo swapoff -a # 临时
根据规划设置主机名
# 设置
hostnamectl set-hostname <hostname>
# 查看
hostname
分别为:
hostnamectl set-hostname master1
hostnamectl set-hostname node1
hostnamectl set-hostname node2
在 master 添加 hosts
cat >> /etc/hosts << EOF
120.25.169.231 master1
120.24.221.223 node1
120.25.205.141 node2
EOF
将桥接的IPv4流量传递到iptables的链
cat > /etc/sysctl.d/k8s.conf << EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system # 生效
时间同步
yum install ntpdate -y #yum更新
ntpdate ntp1.aliyun.com #时间同步
所有节点安装Docker/kubeadm/kubelet
Kubernetes默认 CRI(容器运行时)为Docker,因此先安装Docker。
安装Docker
# centos
wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo
yum -y install docker-ce-18.06.1.ce-3.el7
systemctl enable docker && systemctl start docker
docker --version #Docker version 18.06.1-ce, build e68fc7a
设置Kubernetes镜像源
cat > /etc/yum.repos.d/kubernetes.repo << EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
配置镜像加速器
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://1k8zbux8.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
安装kubeadm,kubelet和kubectl
yum install -y kubelet-1.18.0 kubeadm-1.18.0 kubectl-1.18.0
systemctl enable kubelet #开机启动
部署Kubernetes Master
在Master节点执行.如果是阿里云服务器这里的apiserve需要修改成自己的master内网地址
kubeadm init \
--apiserver-advertise-address=172.28.117.97 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.18.0 \
--service-cidr=10.1.0.0/16 \
--pod-network-cidr=10.244.0.0/16
出现如下信息表示成功
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 172.28.117.97:6443 --token u9e5os.l9tozto1jh4n8bn7 \
--discovery-token-ca-cert-hash sha256:dc644816ced7b82013ac3a6b1d2ad7467b7d33b7e1693dd1d82c9f9126668392
按照提示配置一下内容, 使用kubectl工具:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
加入Kubernetes Node
在Node节点执行
kubeadm join 172.28.117.97:6443 --token u9e5os.l9tozto1jh4n8bn7 \
--discovery-token-ca-cert-hash sha256:dc644816ced7b82013ac3a6b1d2ad7467b7d33b7e1693dd1d82c9f9126668392
默认token有效期为24小时,当过期之后,该token就不可用了。这时就需要重新创建token,操作如下:
kubeadm token create --print-join-command
部署CNI网络插件
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
查看
[root@master1 ~]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-7ff77c879f-m48fj 1/1 Running 0 2m46s
coredns-7ff77c879f-rn6p8 1/1 Running 0 2m46s
etcd-master1 1/1 Running 0 2m55s
kube-apiserver-master1 1/1 Running 0 2m55s
kube-controller-manager-master1 1/1 Running 0 2m55s
kube-flannel-ds-58fb4 1/1 Running 0 83s
kube-flannel-ds-782gl 1/1 Running 0 83s
kube-flannel-ds-qwft4 1/1 Running 0 83s
kube-proxy-455lf 1/1 Running 0 2m35s
kube-proxy-dtbbc 1/1 Running 0 2m31s
kube-proxy-kn7s8 1/1 Running 0 2m46s
kube-scheduler-master1 1/1 Running 0 2m55s
[root@master1 ~]# kubectl get nodes
NAME STATUS ROLES AGE VERSION
master1 Ready master 5m5s v1.18.0
node1 Ready <none> 4m36s v1.18.0
node2 Ready <none> 4m32s v1.18.0
测试Kubernetes集群
在Kubernetes集群中创建一个pod,验证是否正常运行
kubectl create deployment nginx --image=nginx
kubectl expose deployment nginx --port=80 --type=NodePort
[root@master1 ~]# kubectl get pod,svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 10m
service/nginx NodePort 10.1.108.14 <none> 80:32071/TCP 31s
[root@master1 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-f89759699-krhl7 1/1 Running 0 4m5s
访问地址: http://NodePort:Port
http://120.25.169.231:32071/
http://120.24.221.223:32071/
http://120.25.205.141:32071/
资源类型
什么是资源?
k8s中的所有内容都被抽象为资源,资源实例化之后叫做对象.
k8s中存在哪些资源
名称空间级别
工作负载型资源(workload):Pod,ReplicaSet,Deployment,StatefulSet,DaemonSet,Job,CronJob
服务发现及负载均衡型资源(ServiceDiscovery LoadBalance): Service, Ingress …
配置与存储型资源: Volume(存储卷),CSI(容器存储接口)
特殊类型的存储卷: ConfigMap(当配置中心来使用的资源类型),Secret(保存敏感数据),DownwardAPI(把外部环境中的信息输出给容器)
集群级别资源
Namespace,Node,Role,ClusterRole,RoleBinding,ClusterRoleBinding
元数据型资源
HPA,PodTemplate,LimitRange
资源清单
资源清单的含义
在k8s中,一般使用yaml格式的文件来创建符合我们预期期望的pod,这样yaml文件我们一般称为资源清单.
必须存在的属性
参数名 | 字段类型 | 说明 |
---|---|---|
version | String | 这里指的是K8s API的版本,目前基本上是v1,可以用kubectl api-versions 命令查询 |
kind | String | 这里指的是yaml文件定义的资源类型和角色,比如: Pod |
metadata | Object | 元数据对象,固定值就写metadata |
metadata.name | String | 元数据对象的名字,这里由我们编写,比如命名Pod的名字 |
metadata.namespace | String | 元数据对象的命名空间,由我们自身定义 |
spec | Object | 详细定义对象,固定值就写spec |
spec.containers[] | list | 这里是spec对象的容器列表定义,是个列表 |
spec.containers[].name | String | 这里定义容器的名字 |
spec.containers[].image | String | 这里定义要用到的镜像名称 |
示例:pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
namespace: default
labels:
app: myapp
version: v1
spec:
containers:
- name: app
image: nginx
- name: store
image: mysql
容器生命周期
InitC
Pod 能够具有多个容器,应用运行在容器里面,但是他也有可能有一个或多个先于应用容器启动的Init容器.
Init容器与普通的容器非常像,除了以下两点:
1. Init容器总是运行到成功完成为止.
2. 每个Init容器都必须在下一个Init容器启动之前完成.
如果Pod的init容器启动失败,Kubernetes会不断的重启该Pod,直到Init容器成功为止.然而,
如果Pod对应的restartPolicy为Never,它不会重新启动.
Kubernetes Volume
默认情况下容器中的磁盘文件是非持久化的,对于运行在容器中的应用来说面临两个问题:
- 当容器挂掉kubelet将重启启动它时,文件将会丢失;
- 当Pod中同时运行多个容器,容器之间需要共享文件时。Kubernetes的Volume解决了这两个问题。
Kubernetes Volume具有明确的生命周期 - 与pod相同。因此,Volume的生命周期比Pod中运行的任何容器要持久,在容器重新启动时能可以保留数据,当然,当Pod被删除不存在时,Volume也将消失。注意,Kubernetes支持许多类型的Volume,Pod可以同时使用任意类型/数量的Volume。
要使用Volume,pod需要指定Volume的类型和内容(spec.volumes字段),和映射到容器的位置(spec.containers.volumeMounts字段)
Volume 类型
emptyDir
使用emptyDir,当Pod分配到Node上时,将会创建emptyDir,并且只要Node上的Pod一直运行,Volume就会一直存。当Pod(不管任何原因)从Node上被删除时,emptyDir也同时会删除,存储的数据也将永久删除。注:删除容器不影响emptyDir。
示例
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: gcr.io/google_containers/test-webserver
name: test-container
volumeMounts:
- mountPath: /cache
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {}
hostPath
hostPath允许挂载Node上的文件系统到Pod里面去。如果Pod需要使用Node上的文件,可以使用hostPath。
示例
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: gcr.io/google_containers/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
# directory location on host
path: /data
gitRepo
gitRepo volume将git代码下拉到指定的容器路径中。
示例:
apiVersion: v1
kind: Pod
metadata:
name: server
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /mypath
name: git-volume
volumes:
- name: git-volume
gitRepo:
repository: "git@somewhere:me/my-git-repository.git"
revision: "22f1d8406d464b0c0874075539c1f2e96c253775"