容器
容器的兴起
- 容器技术的兴起源于 PaaS 技术的普及;
- Docker 公司发布的 Docker 项目具有里程碑式的意义;
- Docker 项目通过“容器镜像”,解决了应用打包这个根本性难题。
容器是什么
复杂的说
容器其实是一种沙盒技术。顾名思义,沙盒就是能够像一个集装箱一样,把你的应用“装”起来的技术。
简单的说
容器是特殊的进程
如何让进程变得特殊——隔离和限制
Namespace (隔离)和 Cgroups(限制)
Namespace 技术则是欺骗应用进程看待整个计算机“视图”
- PID Namespace,使用参数CLONE_NEWPID,可以在创建的时候虚拟出一个pid;
- Mount Namespace,用于让被隔离进程只看到当前 Namespace 里的挂载点信息;
- Network Namespace,用于让被隔离进程看到当前 Namespace 里的网络设备和配置。
Cgroups 技术是用来制造约束的主要手段
Linux Cgroups 的全称是 Linux Control Group。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。
- 未什么要进行约束?
- 防止容器吃掉系统所有资源
- 常用命令
- mount -t cgroup
rootfs文件系统(容器镜像)
隔离的弊端
- 操作系统的内核不可改变
- 全局时间
总结
- 启用 Linux Namespace 配置;
- 设置指定的 Cgroups 参数;
- 切换进程的根目录(Change Root)。
制作容器镜像
制作基础程序
app.py
from flask import Flask
import socket
import os
app = Flask(__name__)
@app.route('/')
def hello():
html = "<h3>Hello {name}!</h3>" \
"<b>Hostname:</b> {hostname}<br/>"
return html.format(name=os.getenv("NAME", "world"), hostname=socket.gethostname())
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)requirements.txt
FlaskDockerfile
# 使用官方提供的Python开发镜像作为基础镜像
FROM python:2.7-slim
# 将工作目录切换为/app
WORKDIR /app
# 将当前目录下的所有内容复制到/app下
ADD . /app
# 使用pip命令安装这个应用所需要的依赖
RUN pip install --trusted-host pypi.python.org -r requirements.txt
# 允许外界访问容器的80端口
EXPOSE 80
# 设置环境变量
ENV NAME World
# 设置容器进程为:python app.py,即:这个Python应用的启动命令
CMD ["python", "app.py"]build
docker build -f ./Dockerfile -t helloworld .
run
docker run -p 4000:80 helloworld
Kubernetes核心价值
Kubernetes 项目的本质,是为用户提供一个具有普遍意义的容器编排工具。
运行在大规模集群中的各种任务之间,实际上存在着各种各样的关系。这些关系的处理,才是作业编排和管理系统最困难的地方。
- 首先遇到了容器间“紧密协作”关系的难题,于是就扩展到了 Pod;
- 有了 Pod 之后,我们希望能一次启动多个应用的实例,这样就需要 Deployment 这个 Pod 的多实例管理器;
- 而有了这样一组相同的 Pod 后,我们又需要通过一个固定的 IP 地址和端口以负载均衡的方式访问它,于是就有了 Service
Kubernetes组件
Master 组件
Master组件提供集群的管理控制中心。
kube-apiserver API
kube-apiserver用于暴露Kubernetes API。任何的资源请求/调用操作都是通过kube-apiserver提供的接口进行。
ETCD存储系统
etcd是Kubernetes提供默认的存储系统,保存所有集群数据,使用时需要为etcd数据提供备份计划。
kube-controller-manager 容器编排
kube-controller-manager运行管理控制器,它们是集群中处理常规任务的后台线程。逻辑上,每个控制器是一个单独的进程,但为了降低复杂性,它们都被编译成单个二进制文件,并在单个进程中运行。
这些控制器包括:
- 节点(Node)控制器。
- 副本(Replication)控制器:负责维护系统中每个副本中的pod。
- 端点(Endpoints)控制器:填充Endpoints对象(即连接Services&Pods)。
- Service Account和Token控制器:为新的Namespace创建默认帐户访问API Token。
cloud-controller-manager
云控制器管理器负责与底层云提供商的平台交互。云控制器管理器是Kubernetes版本1.6中引入的,目前还是Alpha的功能。
云控制器管理器仅运行云提供商特定的(controller loops)控制器循环。可以通过将--cloud-provider flag设置为external启动kube-controller-manager ,来禁用控制器循环。
cloud-controller-manager 具体功能:
- 节点(Node)控制器
- 路由(Route)控制器
- Service控制器
- 卷(Volume)控制器
kube-scheduler 调度
kube-scheduler 监视新创建没有分配到Node的Pod,为Pod选择一个Node。
插件 addons
插件(addon)是实现集群pod和Services功能的 。Pod由Deployments,ReplicationController等进行管理。Namespace 插件对象是在kube-system Namespace中创建。
DNS
虽然不严格要求使用插件,但Kubernetes集群都应该具有集群 DNS。
群集 DNS是一个DNS服务器,能够为 Kubernetes services提供 DNS记录。
由Kubernetes启动的容器自动将这个DNS服务器包含在他们的DNS searches中。
了解更多详情
用户界面
kube-ui提供集群状态基础信息查看。更多详细信息,请参阅使用HTTP代理访问Kubernetes API
容器资源监测
容器资源监控提供一个UI浏览监控数据。
Cluster-level Logging
Cluster-level logging,负责保存容器日志,搜索/查看日志。
节点(Node)组件
节点组件运行在Node,提供Kubernetes运行时环境,以及维护Pod。
kubelet
kubelet,使用CRI(Container Runtime Interface)的远程调用接口对容器进行控制。
kubelet是主要的节点代理,它会监视已分配给节点的pod,具体功能:
- 安装Pod所需的volume。
- 下载Pod的Secrets。
- Pod中运行的 docker(或experimentally,rkt)容器。
- 定期执行容器健康检查。
插件
- 管理 GPU 物理设备 Device Plugin
- 网络插件 CNI(Container Networking Interface)
- 存储插件 CSI(Container Storage Interface)
kube-proxy
kube-proxy通过在主机上维护网络规则并执行连接转发来实现Kubernetes服务抽象。
docker
docker用于运行容器。
RKT
rkt运行容器,作为docker工具的替代方案。
supervisord
supervisord是一个轻量级的监控系统,用于保障kubelet和docker运行。
fluentd
fluentd是一个守护进程,可提供cluster-level logging.。
对象
服务对象
Secret (密钥管理功能),它其实是一个保存在 Etcd 里的键值对数据。Kubernetes 就会在你指定的 Pod(比如,Web 应用的 Pod)启动时,自动把 Secret 里的数据以 Volume 的方式挂载到容器里。
编排对象
- Job,用来描述一次性运行的 Pod(比如,大数据任务);
- DaemonSet,用来描述每个宿主机上必须且只能运行一个副本的守护进程服务;
- CronJob,则用于描述定时任务;
声明式 API
- 通过一个“编排对象”,比如 Pod、Job、CronJob 等,来描述你试图管理的应用;
- 定义一些“服务对象”,比如 Service、Secret、Horizontal Pod Autoscaler(自动水平扩展器)等。这些对象,会负责具体的平台级功能。
专业术语
编排
编排,是按照用户的意愿和整个系统的规则,完全自动化地处理好容器之间的各种关系。
搭建一个完整的Kubernetes集群
环境准备
修改主机名hostname(在3台机器上分别运行)
hostnamectl set-hostname master01
hostnamectl set-hostname node01
hostnamectl set-hostname node02
检查是否修改完成
hostname
修改hosts文件(在3台机器上分别运行),打开/etc/hosts文件,添加如下,其中ip替换成这3台主机的IP地址
cat >> /etc/hosts << EOF
192.168.86.129 master01
192.168.86.130 node01
192.168.86.131 node02
EOF
source /etc/hosts192.168.86.130 master01
192.168.86.129 node01
192.168.86.131 node02设置免登录(选做,在master上运行)
ssh-keygen
ssh-copy-id root@node01
ssh-copy-id root@node02关闭防火墙(在3台机器上分别运行)
systemctl stop firewalld && systemctl disable firewalld
查看防火墙是否关闭
systemctl status firewalld
关闭selinux(在3台机器上分别运行),禁用文件安全权限,执行如下命令:
sed -i ‘s/enforcing/disabled/’ /etc/selinux/config && setenforce 0
或者直接修改/etc/selinux/config文件
SELINUX=enforcing ===> SELINUX=disabled
检查是否关闭selinux
sestatus
关闭swap(在3台机器上分别运行)
swapoff -a && sed -ri ‘s/.swap./#&/’ /etc/fstab
sysctl --system
检查是否关闭swap
free -mh
如果swap选项下全是0,这表示禁用了空间交换swap
时间同步(选做,在3台机器上分别运行)
yum install ntpdate -y && timedatectl set-timezone Asia/Shanghai && ntpdate time.windows.com
docker会大量操作iptables,需要确认nf-call的值是否为1(在3台机器上分别运行)
echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables
echo 1 > /proc/sys/net/bridge/bridge-nf-call-ip6tablesDocker 安装
更新yum
sudo yum update
安装需要的软件包
yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
设置yum源
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
安装最新版
yum -y install docker-ce
启动docker
systemctl daemon-reload
systemctl start docker
systemctl stop docker
systemctl restart docker
systemctl status docker
systemctl enable docker
修改源
vim /etc/docker/daemon.json
{ “exec-opts”:[“native.cgroupdriver=systemd”]}
sudo systemctl restart dockerkubectl 安装
Linux
下载最新版本的命令:
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl要下载特定版本,请使用特定版本替换$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)命令的一部分。
例如,要在Linux上下载v1.7.0版本,请键入:
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.7.0/bin/linux/amd64/kubectl使kubectl二进制可执行。
chmod +x ./kubectl将二进制文件移动到PATH中。
sudo mv ./kubectl /usr/local/bin/kubectlkubelet和kubeadm 安装
如果使用的是CentOS,请运行:
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
# 安装
yum install -y kubelet kubeadm
# 开机启动
systemctl enable kubelet
# 启动
systemctl start kubelet下载所需的镜像(master)
先查询到kubernetes所需镜像
kubeadm config images list
images=(kube-proxy:v1.20.4 kube-scheduler:v1.20.4 kube-controller-manager:v1.20.4 kube-apiserver:v1.20.4 etcd:3.4.13-0 coredns:1.7.0 pause:3.2)
for imageName in imageName
docker tag /google_containers/imageName
docker rmi /google_containers/$imageName
donedelete.sh
images=(kube-proxy:v1.20.4 kube-scheduler:v1.20.4 kube-controller-manager:v1.20.4 kube-apiserver:v1.20.4 etcd:3.4.13-0 coredns:1.7.0 pause:3.2)
for imageName in {imageName}
done添加执行权限并执行脚本,下载所需要的的镜像
chmod ugo+x
chomd ugo+x delete.sh
./查看所需要的的镜像是否下载成功
docker images
kubeadm init
kubeadm join 命令
kubeadm join 192.168.86.130:6443 --token r774yc.q651j041vr004dc6 --discovery-token-ca-cert-hash sha256:accd26774dccb771068e0b89c7e30dd3a08e81b68990ae3464c4398802b1fa3fKubernetes 集群所需要的配置命令
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config获取唯一节点
kubectl get nodes
部署网络插件
kubectl apply -f “https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d ‘\n’)”
加入Node节点
只在node节点上运行,使用 root 权限登录 Centos7。
1.#下载node节点所需要的镜像
与master类似,脚本文件,内容如下:
images=(kube-proxy:v1.20.4 pause:3.2)
for imageName in imageName
docker tag /google_containers/imageName
docker rmi /google_containers/$imageName
donedelete.sh脚本文件,内容如下:
#!/bin/bash
images=(kube-proxy:v1.20.4 pause:3.2)
for imageName in {imageName}
done2.#添加执行权限并执行脚本,下载所需要的的镜像
chmod ugo+x
chomd ugo+x delete.sh
./3.#拷贝之前master初始化后,生成的kubeadm join命令,具体如下:
kubeadm join 10.0.15.192:6443 --token ptc2mv.z4xyu5z50jg86sze
–discovery-token-ca-cert-hash sha256:a22f5ac5211b03ac92b2d4570fb32f6bee0c81d5cadba0e6d24eeffcaf906ef84.#如果忘记master最后kubeadm init后生成的token和sha256值,解决办法如下:
获取token,在master节点上执行:
kubeadm token list
默认的token的有效期是24小时,可以自己生成永久有效期的token,具体如下:
创建token(24小时过期)
kubeadm token create
生成一条永久有效的token
kubeadm token create --ttl 0
获取sha256,在master节点上执行:
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed ‘s/^.* //’
rancher启动
sudo docker run -d --privileged --restart=unless-stopped -p 80:80 -p 443:443 rancher/rancher设置镜像仓库
从UI导航到Settings,然后编辑system-default-registry,Value设置为
阿里云镜像加速
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://ikpg1kma.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart dockerymal
# yaml格式的pod定义文件完整内容:
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常用命令
删除nodes
删除节点
kubectl delete nodes localhost.localdomain
重置信息
kubeadm reset
















