Kubernetes基本概念和一些未授权访问

Posted by kingkk on 2020-03-19

前言

本文不保证正确性,纯属个人入门笔记

Kubernetes 是一个开源容器编排引擎,用于容器化应用的自动化部署、扩展和管理

随着云时代的到来,各大厂商也都将服务部署在云上了。

k8s作为Google开源的一个容器编排工具,也被国内外不少厂商实践并投入生产使用。随之也催生出了一系列CNCF的云应用,也加速了Go语言的发展。

全面上云,感觉也是个发展的大趋势把,菜如我只能先了解一些基本概念吧…

基本概念

Pod

k8s中最小的调度以资源单元。pod是一个或一组容器的集合。

同一个pod中的容器共享存储、网络、以及怎样运行这些容器的声明 。

相当于一个逻辑主机,同个pod中的不同容器共享网络和上下文资源。

形象来说就是同一组pod中的容器所看到的网络设备、自身的ip地址都是相同的,可以直接通过localhost进行通信。

更加哲学一点的说法就是容器相当于一个进程,而Pod类似于一个进程组,这些进程会共享/同步一些资源,从而协作变成一个统一提供服务的进程组(当然,不需要多个进程的时候,这个进程组中就一个进程,也就只有一个容器)。

Volumne

就是docker中的数据卷,用来管理k8s中的存储。

一个volumne可以被挂载在一个或多个pod的路径中。

volumne其实是一个存储层的抽象,后面实际的实现可以是一些本地存储、分布式存储、云存储之类。

Deployment

Deployment 是在 Pod 这个抽象上更为上层的一个抽象,它可以定义一组 Pod 的副本数目、以及这个 Pod 的版本。

k8s会通过Contorller去维护一个Deployment的状态,例如一些pod的自动恢复,一些版本的升级与回滚。

Service

Kubernetes Service 定义了这样一种抽象:逻辑上的一组 Pod,一种可以访问它们的策略 —— 通常称为微服务。

一组pod的抽象,因为对于用户来说,这一组pod都提供的是同一个服务,就可以把这些pod抽象成一个service。

通过LoadBalancer等方式,相当于对内pod提供了层负载均衡代理,对外用户只要访问指定的service就能被代理到指定服务,而无需关心具体pod。

Namespace

Namespace 是用来做一个集群内部的逻辑隔离的,它包括鉴权、资源管理等。

默认为default,例如一些部门之间的容器隔离和一些权限控制,都可以通过namespace来操作,也解决了一些命名重复的问题。

ReplicaSet

ReplicaSet 确保任何时间都有指定数量的 Pod 副本在运行。 然而,Deployment 是一个更高级的概念,它管理 ReplicaSet,并向 Pod 提供声明式的更新以及许多其他有用的功能。

ReplicaSet对应Deployment template的一个版本。

由Deployment管理ReplicaSet,ReplicaSet管理具体的Pod副本。

例如修改了Deployment中的template,升级了应用的版本,那Deployment则会生成一个新的ReplicaSet。

旧的ReplicaSet删除原先的pod,新的ReplicaSet生成新的pod。

Job

管理任务的控制器。

Job 会创建一个或多个Pod,并确保指定数量的Pod成功终止。

可以跟踪Pod状态,及时重试,以及保证任务执行的循序关系。

还有对应的CronJob,支持定时任务,可以根据cron语法进行定义

DaemonSet

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

例如一些日志收集、和监控的组件,都可以通过DaemonSet的方式进行创建,从而在每个节点上做一个日志收集、监控的操作。

API

交互格式

用户与master交互的方式有两种,一个是通过ui界面操作,还有一个就是通过kubectl进行操作。

但实际上两种的本质都是通过HTTP协议进行传输,格式为JSON/YAML。

例如对某个namespace的某个pod进行操作的url如下。

1
/api/v1/namespaces/$NAMESPACE/pods/$NAME

又或者我们通过apply -f创建pod时,指定的yaml格式如下。

里面分别对应了对这个资源描述的几个部分

  • apiVersion:api的版本信息
  • kind:资源信息
  • metadata:定义name,以及打一些lable或者其他描述
  • spec:期望状态,例如这里指定了container的名字、镜像信息以及对应的端口
  • status:获取资源信息时服务端返回的信息,显示资源的状态

一些字段含义

本来想整理下语法的,后来越整理越多,而且感觉很多对入门选手没太多必要,就挑了几个常见的记录下。

如果想看完整的可以看 https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/ ,对每一个应用都给出了对应的样例,并且介绍了每个字段的含义。

1、lable

一组Key/Value键值对,相当于对当前pod打上标签。

通过selector我们可以选择指定标签的pod,支持一些逻辑条件。

例如Deployment和Service创建时选择指定的pod,就可以通过lable来选择想要的pod。

2、selector

选择器,Deployment和Service创建时选择指定的pod,就可以通过matchLabels的方式选择特定lable的pod。

3、replicas

期望达到的pod数量。例如Deployment创建时期望达到的一个指定的pod数量。

4、template

描述将要被创建的pod的模板。在Deployment创建时指定其生成pod的模板。

5、revisionHistoryLimit

历史ReplicaSet的版本数,默认为10

yaml文件样例

对应一些具体的yaml文件可能会更好理解一些

deployment.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80

service.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion: v1
kind: Service
metadata:
name: my-service
labels:
app: my-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 8888
targetPort: 80
type: LoadBalancer

daemonset.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: daemonset-example
spec:
selector:
matchLabels:
app: daemonset-example
template:
metadata:
labels:
app: daemonset-example
spec:
containers:
- name: daemonset-example
image: ubuntu:trusty
command:
- /bin/sh
args:
- -c
- >-
while [ true ]; do
echo "DaemonSet running on $(hostname)" ;
sleep 10 ;
done

job.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: batch/v1
kind: Job
metadata:
# Unique key of the Job instance
name: example-job
spec:
template:
metadata:
name: example-job
spec:
containers:
- name: pi
image: perl
command: ["perl"]
args: ["-Mbignum=bpi", "-wle", "print bpi(2000)"]
# Do not restart containers after they exit
restartPolicy: Never

kubectl指令

kubectl是用户与master节点进行通信的cli,完整的指令文档在 https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands

我就只介绍几个常见的命令操作

基本的命令格式如下

1
kubectl [command] [TYPE] [NAME] [flags]

常见的command操作有

  • create : 创建资源
  • get : 获取资源信息
  • describe :获取特定资源的详细描述
  • delete : 删除资源

例如

1
2
3
4
5
6
7
8
9
kubectl get nodes // 获取nodes节点信息
kubectl get pods // 获取pods信息
kubectl get deployment // 获取deployment信息
kubectl get services // 获取service信息
kubectl describe deployment nginx-deployment // 查看deployment描述
kubectl delete deployment nginx-deployment // 删除指定deployment
kubectl edit deployment nginx-deployment // 编辑指定deployment
kubectl apply -f example-service.yaml // 使用 example-service.yaml 中的定义创建服务。
kubectl exec -it podname sh // 执行指定pod操作

简写风格

kubectl还支持一部分简写,例如pod和pods,deployment和deployments其实是不区分的。

不仅如此,还有更大幅度的简写

  • pods : po
  • namespace : ns
  • nodes : no
  • services : svc
  • deployments : deploy

输出选项

-o--ouput参数 可支持格式化输出

  • -o wide 纯文本输出,但包含的信息内容更多
  • -o name仅输出名字
  • -o yaml yaml格式输出
  • -o json json格式输出

k8s组件

基本架构,我们主要通过cli或者web ui的方式去操控master节点(或者说是向master节点发送请求),再由master节点来总的管理我们的node节点。

Master组件

kube-apiserver

主节点上负责提供 Kubernetes API 服务的组件;它是 Kubernetes 控制面的前端。

别的组件都会与apiserver进行交互,相当于master中一个总的操作中心。

controller-manager

对集群状态的管理,比如一些扩缩容和一些修复之类的操作。

在文档中还分为kube-controller-manager和云控制器管理器-(cloud-controller-manager)。

kube-scheduler

相当于一个调度器,对目前拥有的资源的调度。

例如要创建一个pod时,scheduler就会选择一个合适的node节点来创建pod。

etcd

etcd 是兼具一致性和高可用性的键值数据库,可以作为保存 Kubernetes 所有集群数据的后台数据库。

一个分布式存储系统,存放一些k8s所需的元信息。

etcd也不仅可用于k8s,也可以用于一些服务发现的场景。

Node组件

kubelet

一个在集群中每个节点上运行的代理。它保证容器都运行在 Pod 中。

与master中的kube-apiserver做交互的组件,接受master发送的消息,然后做对应处理。

个人理解相当于node中的apiserver。

kube-proxy

kube-proxy是集群中每个节点上运行的网络代理,实现 Kubernetes Service概念的一部分。

kube-proxy 维护节点上的网络规则。这些网络规则允许从集群内部或外部的网络会话与 Pod 进行网络通信。

相当于一个流量的代理层,用于后续将一系列node节点在网络层面结合成一个总的service。

Container Runtime

容器运行环境是负责运行容器的软件。

真正实际运行容器的部分,这里的容器不仅限于Docker。

Addons

网络和存储的一些管理并不由k8s直接操作。

一般会由云厂商,或者k8s的使用方来描述如果做网络与存储的操作。

就可以通过插件的形式,来告诉k8s具体如何去做网络与存储之类的操作。

(文档中还有提到一些ui,资源监控的插件)

一次pod创建过程

可以来看下一次pod创建过程中,这些组件是如何相互协调工作的。

1、用户通过cli或者ui向master节点提交一次pod创建的请求。

2、master节点中的api-server接受到请求之后,将创建请求写入etcd中。

3、scheduler通过 watch 或者叫做 notification 机制从api-server中得到一个pod需要被创建的消息。

4、scheduler根据将被创建的pod资源进行一次决策,决定改pod在哪个node中被创建,并将消息发送个api-server。

5、api-server将要创建的信息存入etcd中,并将创建信息发送给对应的node节点。

6、node节点中的kubelet接受到创建node的消息之后,通过container runtime实际去启动容器,并调用所需的插件。

未授权访问利用

k8s的master节点上会暴露kube-apiserver,默认情况下会开启两个HTTP端口

1)本地主机端口

  • HTTP服务
  • 默认端口8080,修改标识–insecure-port
  • 默认IP是本地主机,修改标识—insecure-bind-address
  • 在HTTP中没有认证和授权检查
  • 主机访问受保护

2)Secure Port

  • 默认端口6443,修改标识—secure-port
  • 默认IP是首个非本地主机的网络接口,修改标识—bind-address
  • HTTPS服务。设置证书和秘钥的标识,–tls-cert-file,–tls-private-key-file
  • 认证方式,令牌文件或者客户端证书
  • 使用基于策略的授权方式

之前也提到过,可以通过ui接口进行管理和配置k8s。如果ui接口可以被我们未授权访问的话,我们就可以利用它来搞一些事情。

直接访问会返回可用的API列表

看别人的说法是访问/ui就可以到对应的dashboard界面,我这边是用minikube起的,貌似有些差异,访问的是/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/但问题不大

我们通过ui界面创建一个pod,并将本地根目录挂载到pod的/mnt目录中

创建Pod的yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- image: nginx:1.7.9
name: container
volumeMounts:
- mountPath: /mnt
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /

这样,过一会之后就能看到我们创建的myapp Pod以及run起来了

通过右上角进入Pod的shell控制台

这样,进入挂载好的/mnt目录中,就是master节点的对应目录了

后面写cron之类的操作就不演示了。

kubectl也可以通过-s http://master-hostname:port 的方式来连接特定的未授权访问端口。

但是想exec执行命令时却被Forbidden了,不知道是我环境问题,还是k8s策略的原因

其余的未授权访问之类的还有如下,链接中也有比较详细的利用方式 https://www.freebuf.com/vuls/196993.html

  • etcd 2379端口:默认通过证书认证,主要存放节点的信息,如一些token和证书。
  • kubelet 10250端口:默认也是通过证书认证,与master节点交互的端口,如果可以利用可以直接控制该node的所有pod。
  • docker rest-api 2375端口:其实和k8s关系不大,主要是docker服务的rest接口。

References

https://kubernetes.io/zh/docs/home/

https://edu.aliyun.com/roadmap/cloudnative

https://www.bilibili.com/video/av85429526

https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/

https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands

https://www.freebuf.com/vuls/196993.html

https://www.mls-tech.info/docker/k8s-installation-on-ubuntu1804/