K8s Docker 学习笔记
K8s
K8s 安装 TODO
K8s架构图
K8s 常见概念
Resource
Resource 是 Kubernetes 的一个基础概念,kubernets 用 Resource 来表示集群中的各个资源。比如 Pod 节点(主机)、Container 容器、Proxy 路由、Config 配置文件等等。这些概念听起来差别很大,但是却有很多共同的基本属性。比如名称、创建时间、标签、uuid 等。kubernetes 对这些信息进行抽象,提供了一个通用的 metadata 结构,再加上各个 resource 自己的其它信息,构成了一个形式类似的数据结构。
Namespace
namespace 的作用是用于名称隔离。kubernetes的场景是面向多用户的,需要有一个类似于工作空间的东西用来隔离。
集群创建之后,会默认创建三个namespace:
- default:默认的namespace
- kube-system:系统的namespace
- kube-public:存放系统信息的namespace,一般不需要关注
定义Context(运行环境)
ConfigMap
ConfigMap是属于namespace的资源,像环境变量或者很多软件的配置文件,存储了一些key-value。
Secret
Secret对象可以存储和管理敏感信息
- 创建Pod时,通过为Pod指定Service Account自动使用该Secret
- 通过挂载Secret到Pod来使用它
- 在Docker镜像下载时使用,通过指定Pod的spec.ImagePullSecrets来引用它
三种创建Secret的方法
- 从文件创建
kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt
- 创建yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret-2
type: Opaque
stringData:
config.yaml: |-
apiUrl: "https://my.api.com/api/v1"
username: admin
password: 1f2d1e2e67df
StringData字段下的所有条目会被Base64编码之后展示在data字段下
- 使用生成器创建Secret
[TO DO]
ServiceAccount
认证主要供集群内部Pod中的进程使用,以便Pod可以从内部使用API Server
默认会创建default的ServiceAccount关联着一个名为default-token-v6wkr
的Secret,里面存放着ServiceAccount的认证信息,这些认证信息可以访问API Server
API SERVER 的身份验证、授权、准入控制
访问API-SERVER需要经过
- 身份认证
- 授权
K8s默认启用的是RBAC授权方式 - 准入控制
RBAC授权方式
- 角色定义
- 角色绑定
- User
- ServiceAccount
使用Secret的三种方式
- 使用挂载的方式
spec:
containers:
- name: mypod
image: redis
volumeMounts:
- name: foo
mountPath: '/etc/foo'
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
- 使用环境变量的形式
spec:
containers:
- name: mycontainer
image: redis
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
- 使用镜像拉取Secret(ImagePullSecrets)
- 创建包含Docker镜像仓库证书的Secret
- 在Pod定义中使用字段ImagePullSecrets引用Secret
etcd
k8s的存储组件,k8s中的数据主要都存在于其中
apiserver
k8s对外提供API服务的组件,也主要负责与etcd交互
scheduler
负责调度pod的组件。当我们想在一堆机器中运行pod时,负责决定将pod运行在哪个机器上
Pod
Pod 基本结构
- apiVersion/kind:这是所有资源共有的基本字段,表示api版本号以及类型
- metadata
- name:这个pod的名字
- labels: pod标签
- namespace:可选字段 如果yaml不写namespace,表示default namespace
- spec:pod的主要信息部分
- containers:一个列表
- container
- name:此container的名字
- image:镜像信息
- command:启动命令,一般的镜像都是有默认值
- container
- containers:一个列表
pod 基本状态
- phase:pod的状态
- Pending:一般表示还没有开始调度到某台机器上。如果没有符合条件的主机,就会一直处于Pending状态
- Running:运行中
- Succeeded:一段时间就退出的Pod,反馈任务执行的结果
- Failed:command写的有问题
- Unknown:未知
- qosClass:资源分配相关
- Guaranteed: requests = limits K8s只要使用资源不超过limits就不会被kill
- Burstable:requests < limits,Pod可以使用requests到limits之间数量的资源。但是当机器资源使用紧张的时候,如果这些的Pod对资源的使用超过requests,就很有可能会被kill掉
- BestEffort:没有设置具体的requests和limits。如果机器资源紧张,会优先被kill掉
requests: pod运行所需要的最少资源,例如K8s在调度pod时,就是以这个设置来挑选node
limits:pod运行的上限,超过这个limits,pod会被kill掉
Pod启动命令
- pod 不设置任何参数,直接用镜像里面自带的参数
- pod 的 command 和 args 都设置,使用设置的命令和参数
- pod 只设置 command ,完全忽略镜像里的参数
- pod 只设置 args,镜像中的命令与新参数一起使用
InitContainers
- 是短期运行的程序,不是持久运行的进程
- 顺序执行,并且每一个initContainer必须等待前一个执行成功才能继续执行
例如某一个服务的运行,需要一些前置条件(服务依赖,文件等等)才能正常执行。初始化容器的目的是将初始化与主体逻辑分离并放置在不同的镜像中
正式容器运行阶段回调函数
如果要在容器创建后或停止前执行某些操作,则可以注册以下两个事件的回调
- PostStart: 容器刚刚创建成功后,触发事件,执行回调
- PreStop: 容器开始和结束前,触发事件,执行回调
回调的方式有两种(一种是Exec,一种是HttpGet)
Pod的健康检查
设置探针
- 存活探针(livenessProbe):测定容器是否正在执行。如果存活探针返回Failure,kubelet会终止容器,然后容器会遵循其重启策略
- 就绪探针(readinessProbe):测定容器是否已准备好为请求提供服务。如果就绪探针返回Failure,Endpoint控制器会从所有Service的Endpoint中移除Pod的IP地址
Deployment
Deployment控制器旨在简化Pod的生命周期管理。只需要简单更改Deployment控制器的配置文件,K8s就会自动调节Replicas控制器,管理应用程序不同版本之间的切换
Deployment的更新
- Recreate:所有现有的Pod都会在创建新的Pod之前被终止
- RollUpdate:表示以滚动的方法更新Pod
- maxUnavailable: 表示在更新过程中能够进入不可用状态的Pod的最大值或相对于总副本数的最大百分比(在更新过程中,可以忍受多少个Pod无法提供服务)
- maxSurge:表示能够额外创建的Pod数或相对于总副本数的百分比(在滚动更新的时候,可以有多少个额外的Pod)
Deployment的升级方式
kubectl set image deployment/ngxin-deployment nginx=nginx:1.9.1
# 也可以使用kubectl edit命令进行更新,把image字段修改版本
kubectl edit deployment/nginx-deployment
更新的暂停与恢复
目前无论是直接更新还是滚动更新,都会一直持续更新
可以尝试一个最新的Pod,待这个Pod验证无误后,再更新剩余的Pod
kubectl set image deploy exampledeployment nginx=nginx:1.9.1 --record
# --record 必须携带上,这样才会记录Deployment所使用的命令
kubectl rollout pause deploy exampledeployment # 暂停更新
kubectl rollout resume deploy exampledeployment # 恢复更新
kubectl rollout history deployment exampledeployment # 查看历史变更记录
kubectl rollout undo deployment exampledeployment --to-revision=2 # 回滚上个版本
DaemonSet
DaemonSet是一种特殊的控制器,会在集群中的各个节点上运行单一的Pod,它非常适合部署那些为节点本身提供服务或执行维护的Pod
更新策略
- RollUpdate:
- OnDelete:只有手动删除旧的DaemonSet控制器Pod后,才会创建新的DaemonSet控制器Pod
Job和CronJob
- 一次性任务
Job执行完之后不会自动删除 - 串行式任务
spec:
completions: 5 # 执行5次
- 并行式任务
spec:
completions: 11
parallelism: 5
Job的重启策略
- OnFailure
OnFailure,在失败的时候会重新启动Pod,达到最大次数之后会删除Pod
spec:
backoffLimit: 6
template:
spec:
restartPolicy: OnFailure
- Never
Never,在失败时不会重新启动Pod,而是会新建新的Pod,达到最大次数之后会保留现场,方便排查问题
spec:
backoffLimit: 6
template:
spec:
restartPolicy: Never
执行任务达到上限时间会自动删除Pod
spec:
activeDeadlineSeconds: 10
Service
Service 3种向外发布的方式
- ClusterIP-普通Service:在K8s集群内部发布服务时,会为Service分配一个集群内部可以访问的固定虚拟IP。集群中机器和集群中Pod都可以访问的固定虚拟IP
- NodePort:这种方式基于ClusterIP方式,先生成ClusterIP地址,然后将这个IP地址及端口映射到各个集群机器(Master和Node)到指定端口上,K8s外部到机器可以通过NodeIP:Node端口方式访问Service
- LoadBalancer:这种方式基于ClusterIP方式和NodePort方式,还会申请负载均衡器(TODO)
Service 2种向内发布的方式
- Cluster-无头Service(headless service):这种方式ClusterIP,通过DNS提供稳定的网络ID来进行访问
- ExternalName:将外部服务引入进来,通过一定格式映射到K8s集群,从而为集群内部提供服务
4种IP
ClusterIP
:这是一种虚拟IP,没有实际的网络设备承载这个地址,它的底层实现原理是依靠kube-proxy通过iptables规则重定向到Node节点的端口上,再负载均衡到后端PodNodeIP
:当集群需要提供外部服务,这时候就需要为服务提供公共IP,集群外部通过nodeIP:nodePort就可以访问服务PodIP
:当每个新 Pod 创建时,集群都会先使用gcr.io/google_containers/pause
镜像创建一个容器,然后再创建其它要求的容器。在 Pod 内部其它容器都使用container
网络模式,并指定其值为 pause 容器的 ID(即:"network_mode: "container: pause 容器 ID"
),这样 Pod 内所有容器将共享 pause 容器的网络,所有其他容器在 Pod 内部都处于同一个网络模式下,可以彼此间直接通信,而与外部通信都会经过 pause 容器进行代理,因此 pause 容器 IP 才是真正实际意义上的 PodIP。ExternalIP
:外部 IP,通过负载均衡(LB)方式发布服务的话,也就是 LoadBalancer Service 类型,公有云提供的负载均衡器的访问地址。
3种Port
- port:service暴露在cluster ip上的端口,:port是提供给集群内部客户访问service的入口
- nodePort:是k8s提供给集群外部客户访问service入口的一种方式
- targetPort是pod上的端口,从pod和nodePort上到来的数据最终经过kube-proxy流入到后端targetPort上进入容器
Service服务发现
- 环境变量
在Node上新创建一个Pod,Kubelet会为每个Pod添加一个组环境变量。服务必须先于Pod创建。如果先创建Pod后创建Service,那么后创建的Service环境变量不会存在先创建的Pod中 - DNS
集群中所有Pod可以通过DNS名称自动解析服务,而具体的实现是通过修改每个容器的/etc/resolv.conf实现的。
Ingress
通过Service和ExternalIP等等,这些方式都是通过节点端口向外暴露服务的,一旦Service变多,每个节点上开启的端口也会变多,维护起来相当复杂。
Ingress 可以避免这个问题,除了Ingress自身的服务需要向外发布之外,其他服务不必使用节点端口形式向外发布。
四,七层负载均衡
- 四层:主要分析IP层及其TCP/UDP层,实现四层负载均衡。此种负载均衡器不理解应用协议(如HTTP/FTP/MySQL等等)
- 七层:除了支持四层负载均衡以外,还有分析应用层的信息,如HTTP协议URI或Cookie信息,实现七层负载均衡。此种负载均衡器能理解应用协议。
Ingress Ingress Controller
- Ingress: Ingress 资源对象,使用YAML文件来定义负载均衡的策略(规则)
- Ingress Controller:控制器,以插件形式存在于集群中,从apiServer中获取Ingress的规则变化
在集群中,需要先部署 Ingress Controller,再创建 Ingress 资源对象。Ingress Controller 控制器是一个 docker 容器,容器镜像中包含一个负载均衡器(比如:Nginx 或是 HAProxy)和一个 Ingress Controller。 - 方式
当集群使用 Ingress 进行负载分发时,Ingress Controller 基于 Ingress 规则将客户端请求直接转发到 Service 对应的后端 Endpoint(Pod) 上,所以会跳过 kube-proxy 的转发功能,kube-proxy 在这里并不会起作用。这种方式比 LoadBalancer 更加高效。
curl https://www.lanqiao.cn/courses
# 请求会被路由到后端名为courses的Service
存储与配置
emptyDir
emptyDir是指一个纯净的空目录,这个目录映射到主机的一个临时目录下,如果Pod销毁,那么存储卷也会同时销毁,emptyDir主要用于存放和共享Pod的不同容器之间在运行过程中产生的文件
hostPath
hostPath主要用于把主机上指定的目录映射到Pod中容器上,如果Pod需要在主机上存储和共享文件,或使用主机上的文件,就可以使用这种方式。
存放在主机上的文件不会被销毁,会永远保存,Pod销毁后,若又在这台机器上重建,则可以读取原来的内容,但如果机器出现故障或者Pod被调度到其他机器上,就无法读取原来的内容了。
PV PVC StorageClass
- PV 定义了K8s集群中可用的存储资源,其中包含存储资源实现的细节
- PVC表示持久存储卷的申请,是由用户发起的对存储资源的请求。申请中只包含请求资源的大小和读写访问模式,无须关注具体的资源实现细节(PV和PVC只能一对一绑定,不能一对多绑定)
- StorageClass是通过分配器来动态分配PV的
StatefulSet控制器
是一种提供排序和唯一性保证的特殊Pod控制器。当有与部署顺序、持久数据或固定网络等相关的特殊需求时,可用StatefulSet控制器来进行更细粒度的控制(对应于有状态服务)
Docker
Docker底层原理
Docker是一个Client-Server结构的系统,Docker的守护进程运行在主机上,通过Socket从客户端访问。
为什么Docker比Vm快?
- docker有着比虚拟机更少的抽象层。由于docker不需要Hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。
- docker利用的是宿主机的内核,而不需要Guest OS。
Docker 镜像
是Docker容器运行的只读模板,每一个镜像由一系列的层layer组成。通过镜像可以创建多个容器
Docker容器
是基于镜像启动起来的,容器中可以运行一个或多个进程。容器之间是相互隔离的
镜像是docker生命周期中的构建和打包阶段,而容器则是启动或执行阶段
Docker启动就退出的原因
Docker容器中进程pid=1的进程退出后,容器就结束了,docker容器运行必须有一个前台进程, 如果没有前台进程执行,容器认为空闲,就会自行退出。
Docker 基本命令
docker info
docker version
docker images # 查看所有本地主机上的镜像
docker images -aq # 列出所有镜像的id
docker search # 搜索镜像
docker pull # 下载镜像
docker pull tomcat[:tag] # 下载指定版本的镜像
docker rmi -f 镜像id
docker rmi -f ${docker ps -aq} # 删除所有的镜像
# 容器命令
docker run 镜像id # 新建容器并且启动
docker ps # 列出所有运行的容器 docker container list
docker rm 容器id # 删除指定的容器,不能删除正在运行的容器
docker rm -f ${docker ps -aq} # 删除所有的容器
docker ps -a -q|xargs docker rm # 删除所有的容器
# 新建容器并且启动
docker run [] image
--name="Name" # 容器的名字 tomcat01, tomcat02 用来区别容器
-d # 后台的方式运行
-it # 使用交互方式进行,进入容器中查看内容
-p # 指定容器的端口
-P # 随机指定端口
docker run -it centos /bin/bash
# 退出容器
ctrl + P + Q # 容器不停止退出
exit # 容器直接退出
# 查看日志
docker logs [-tf --tail number] 容器id
[-t] # 显示时间戳
[-f] # 追踪日志
[--tail number] # 显示最后几条日志条数
docker logs -t --tail n 容器id # 查看n行日志
docker logs -tf 容器id # 跟着日志
# 查看容器中进程的信息ps
docker top 容器id
# 查看容器中的元数据
docker inspect 容器id
# 进入当前正在运行的容器
# 通常容器都是使用后台进行运行的,需要进入容器,修改一些配置
1. docker exec -it 容器id /bin/bash # 进入容器后开启一个新的终端,可以在里面操作
2. docker attach 容器id # 进入容器正在执行的终端
# 从容器内拷贝到主机上
docker cp 容器id:容器内路径 主机目的路径
# 区别三种挂载方式
-v 容器内路径 # 匿名挂载
-v 卷名: 容器内路径 # 具名挂载
-v /宿主机路径: 容器内路径 # 指定路径挂载 docker volume ls 查看不到
# ro rw 改变读写权限
docker run -d -P --name nginx05 -v juming:/etc/nginx:ro nginx
docker run -d -P --name nginx05 -v juming:/etc/nginx:rw nginx
# ro 说明这个路径只能通过宿主机来操作,容器内部是无法操作
数据卷容器
两个或者多个容器之间实现数据共享
docker run -it -name docker01 huyuanyuan/centos
docker run -it --name docker02 --volumes-from docker01 huyuanyuan/centos
docker run -it --name docker03 --volumes-from docker01 huyuanyuan/centos
# 删除docker01, 查看docker02 docker03 可以访问这个文件
# 容器之间的配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。
# 如果持久化到了本地,本地的数据是不会被删除的