Kubernetes is an open source container orchestration engine for automating deployment, scaling, and management of containerized applications.
Traditional:
物理机无法定义资源边界以及隔离资源,难以合理分配资源
Virtualized:
虚拟机技术使应用得以隔离,隔离层级最高
Container:
容器化技术降低了隔离层级,共享OS,但每个容器有自己的文件系统、CPU、内存、进程空间。部署容易快速。
容器其实是一种沙盒技术。顾名思义,沙盒就是能够像一个集装箱一样,把你的应用“装”起来的技术。这样,应用与应用之间,就因为有了边界而不至于相互干扰
可以说,容器封装了应用软件本身以及软件运行起来需要的依赖
启动一个容器
docker run -it busybox /bin/sh
ps -ef
docker inspect
从以上观察可以得知,容器
实际上就是系统本身的一个进程,而容器里面所执行的命令程序,都是这个进程的子进程
docker run -it busybox /bin/sh
/ # pwd
/
/ # ls
bin dev etc home proc root sys tmp usr var
/ #
/ # ps -ef
PID USER TIME COMMAND
1 root 0:00 /bin/sh
7 root 0:00 ps -ef
/ #
/ #
/ #exit
root@ubuntu:~# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2ad429d5fce9 busybox "/bin/sh" 7 minutes ago Exited (0) 3 seconds ago elegant_cartwright
root@ubuntu:~#
那么容器是如何实现内部进程的变化,如何实现对系统本身的进程隔离呢?
容器技术的核心功能,就是通过约束和修改进程的动态表现,从而为其创造出一个“边界”。
Linux Namespaces机制提供一种资源隔离方案。Mount、UTS、IPC、Network 和 User等系统资源不再是全局性的,而是属于某个特定的Namespace。每个namespace下的资源对于其他namespace下的资源都是透明,不可见的。
Mount Namespace,用于让被隔离进程只看到当前 Namespace 里的挂载点信息;Network Namespace,用于让被隔离进程看到当前 Namespace 里的网络设备和配置。
Namespace 技术实际上修改了应用进程看待整个计算机“视图”,即它的“视线”被操作系统做了限制,只能“看到”某些指定的内容。
Linux Cgroups 的全称是 Linux Control Group。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。
镜像是封装好的运行环境,镜像运行之后变成容器。即镜像是静态的,容器是动态的。
Client
用户与Dokcer交互的方式
Docker daemon
监听用户请求以及管理镜像、容器、网络以及数据卷
Registry
存放镜像的仓库,分为公有与私有仓库
K8S集群由一组节点组成,节点分为Master和Worker,两种节点上面部署的组件是不同的。
- 提供 Kubernetes API,Kubernetes控制平台的前端。
kubectl / kubernetes dashboard / kuboard 等Kubernetes管理工具就是通过 kubernetes API 实现对 Kubernetes 集群的管理。
- 提供了资源操作的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制;
- Kubernetes集群的所有配置信息都存储在 etcd 中,保存了整个集群的状态
- 监控所有新创建尚未分配到节点上的 Pod,并且自动选择为 Pod 选择一个合适的节点去运行
运行了所有的控制器
节点控制器: 负责监听节点停机的事件并作出对应响应
副本控制器: 负责为集群中每一个 副本控制器对象(Replication Controller Object)维护期望的 Pod 副本数
端点(Endpoints)控制器:负责为端点对象(Endpoints Object,连接 Service 和 Pod)赋值
Service Account & Token控制器: 负责为新的名称空间创建 default Service Account 以及 API Access Token
(1)Container Runtime
- 容器引擎,如Dokcer,还有其他的如containerd、cri-o、rktlet等
(2)kubelet
- 通过Restapi与apiserver交互
- 直接和Container Runtime交互,解析apiserver的指令,转化成Container Runtime能识别的命令
- 保证容器(containers)都 运行在 Pod,确保pod处于运行状态且健康
- 上报worker节点状态
(3)kube-proxy
- 在节点上维护网络规则,是实现Pod、集群与集群外网络的重要组件
Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。
Pod 容器组 是一个k8s中一个抽象的概念,用于存放一组 container(可包含一个或多个 container 容器,即图上正方体),以及这些 container (容器)的一些共享资源。具体的说:Pod 里的所有容器,共享的是同一个 Network Namespace,并且可以声明共享同一个 Volume。。
在 K8s 里,Pod 的实现需要使用一个中间容器,这个容器叫作 Infra 容器。在这个 Pod 中,Infra 容器永远都是第一个被创建的容器,而其他定义的容器,可以共享这个Infra容器的资源
## infra容器使用的是k8s.gcr.io/pause镜像
root@ubuntu:~# docker ps | grep pause
88e0772f6dba rancher/pause:3.2 "/pause" 7 minutes ago Up 7 minutes k8s_POD_two-containers_default_6215844f-6885-4c37-a96b-e6a2e79c9f3b_0
网络Namespace共享: 一个 Pod 只有一个 IP 地址,也就是这个 Pod 的 Network Namespace 对应的 IP 地址;
Volume可以共享:
apiVersion: v1
kind: Pod
metadata:
name: two-containers
spec:
restartPolicy: Never
volumes:
- name: shared-data
hostPath:
path: /data
containers:
- name: nginx-container
image: nginx
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
- name: debian-container
image: debian
volumeMounts:
- name: shared-data
mountPath: /pod-data
command: ["/bin/sh"]
args: ["-c", "echo Hello from the debian container > /pod-data/index.html"]
由此可知,Infra容器与Pod的生命周期是一致的,同生共死,与其他容器无关
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
# image: nginx
ports:
- containerPort: 80
ClusterIP
kubectl expose --name clusterip-svc deployment/nginx-deployment --type=ClusterIP
ExternalIP
kubectl --name externalip-svc expose deployment/nginx-deployment --type=ClusterIP --external-ip=80.1.1.1
NodePort
kubectl expose --name nodeport-svc deployment/dnginx-deployment --type=NodePort
LoadBalance
多个worker节点时,利用LoadBalance对外暴露一个IP+Port,实现流量负载均衡
PV 描述的,是持久化存储数据卷。这个 API 对象主要定义的是一个持久化存储在宿主机上的目录,比如一个 NFS 的挂载目录
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
nfs:
server: 10.244.1.4
path: "/"
PVC 描述的,则是 Pod 所希望使用的持久化存储的属性。比如,Volume 存储的大小、可读写权限等等。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs
spec:
accessModes:
- ReadWriteMany
storageClassName: manual
resources:
requests:
storage: 1Gi
PVC 可以理解为持久化存储的“接口”,它提供了对某种持久化存储的描述,但不提供具体的实现;而这个持久化存储的实现部分则由 PV 负责完成。
人工管理PV与PVC的配置使PV与PVC绑定的方式为Static Provisioning
大规模集群不方便人工管理PV与PVC绑定操作
Dynamic Provisioning 机制工作的核心,在于一个名叫 StorageClass 的 API 对象。而 StorageClass 对象的作用,其实就是创建 PV 的模板。
StorageClass的工作方式:
Kubernetes 就能够根据用户提交的 PVC,找到一个对应的 StorageClass 了。然后,Kubernetes 就会调用该 StorageClass 声明的存储插件,创建出需要的 PV。
在K8S中,一个 API 对象在 Etcd 里的完整资源路径,是由:Group(API 组)、Version(API 版本)和 Resource(API 资源类型)三个部分组成的。
声明创建一个Deploymen对象,那么yaml文件如下所示:
apiVersion: apps/v1
kind: Deployment
...
在上面的配置中,Deployment就是API对象的资源类型,apps就是Group,而v1就是Version。
获取所有的api-resource
root@ubuntu:~# kubectl api-resources
NAME SHORTNAMES APIGROUP NAMESPACED KIND
CRD的全称是 Custom Resource Definition,即自定义API资源
root@ubuntu:~# kubectl get crd | grep axyom.casa.io
casa的4、5G网元有特别多的属性配置,K8S本身的API并不足以支持,需要将API资源实例化需要CRD
环境中会有一个operator pod负责实际自定义API对象的部署与运维
环境中会有一个apiserver pod可以获取到自定义对象的状态与信息
docker version # 显示docker的版本信息
docker info # 显示 Docker 系统信息,包括镜像和容器数
docker 命令 --help # 帮助命令
https://docs.docker.com/engine/reference/commandline/docker/
root@ubuntu18:~# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 4bb46517cac3 2 weeks ago 133MB
hello-world latest bf756fb1ae65 8 months ago 13.3kB
root@ubuntu18:~#
# 解释
REPOSITORY 镜像的仓库源
TAG 镜像的标签
IMAGE ID 镜像的ID
CREATED 镜像创建时间
SIZE 镜像的大小
# 可选项
-a, --all Show all images
-q, --quiet Only show numeric IDs
root@ubuntu18:~# docker search mysql
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 9911 [OK]
mariadb MariaDB is a community-developed fork of MyS… 3627 [OK]
mysql/mysql-server Optimized MySQL Server Docker images. Create… 720 [OK]
# docker pull 镜像名[:TAG]
root@ubuntu18:~# docker pull mysql
Using default tag: latest ## 如果不写tag,默认是latest
latest: Pulling from library/mysql
bf5952930446: Already exists ## 分层下载,docker image的核心 联合文件系统
8254623a9871: Pull complete
938e3e06dac4: Pull complete
ea28ebf28884: Pull complete
f3cef38785c2: Pull complete
Digest: sha256:c358e72e100ab493a0304bda35e6f239db2ec8c9bb836d8a427ac34307d074ed
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest ## 镜像在仓库的真实地址
## 以下等价
docker pull mysql:latest
docker pull docker.io/library/mysql:latest
## docker rmi 镜像名/镜像ID
root@ubuntu18:~# docker rmi mysql
# 删除多个镜像
docker rmi 镜像ID 镜像ID ...
# 删除全部镜像
docker rmi $(docker images -aq)
# 可选项
-f 强制删除
## docker tag 源镜像名/源镜像ID[:TAG] 目标镜像名[:TAG]
docker tag a5a2298be7c0 registry.gitlab.casa-systems.com/mobility/amf/n2mgr:latest
docker run [可选参数] image
# 可选项
--name string assign a name to the container<分配容器名>
-d, --detach Run conatiner in the background<后台运行>
-it 使用交互方式运行,进入容器内查看内容
-p 指定容器的端口
-p ip:主机端口:容器端口
-p 主机端口:容器端口 #(主机端口映射容器端口,常用)
-p 容器端口
-P 随机指定端口
# 启动并进入容器
root@ubuntu18:~# docker run -it centos /bin/bash
[root@251c933af480 /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@251c933af480 /]#
docker ps [可选参数]
# 列出正在运行的容器
docker ps
# 可选参数
-a 列出所有容器
-n=? 显示最近创建的n个容器
-q 只显示容器ID
# 删除指定容器,不能删除正在运行的容器
docker rm 容器名/容器ID
# 强制删除
docker rm -f 容器名/容器ID
# 删除全部容器
docker rm -f $(docker ps -aq)
docker start/stop 容器名/容器ID # 开始或停止容器的运行
docker restart 容器名/容器ID # 重启容器
docker kill 容器名/容器ID # 强制停止当前容器
# docker run -d 镜像名
docker run --name centos1 -d centos /bin/bash
# 启动后docker ps发现容器已经停止
# docker容器后台运行,必须要有一个前台进程,docker发现没有应用运行,就会自动停止
root@ubuntu18:~# docker run -it --name centos1 -d centos /bin/bash
b307f4a05b3e1202c46fa84200c840a980a135fca712f9a977f5cae9a2404b72
root@ubuntu18:~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0963075e55c9 centos "/bin/bash" 6 minutes ago Up 6 minutes centos1
docker logs 容器ID
可选参数:
-f 实时打印log
-t 打印时间戳
--tail n 打印最后n行log
docker top 容器ID
root@ubuntu18:~# docker top 02e048310a44
UID PID PPID C STIME TTY TIME CMD
root 26612 26584 99 13:47 ? 00:03:36 /bin/bash -c while true;do echo lixuanwen;done
docker inspect NAME/ID
root@ubuntu18:~# docker inspect 02e048310a44
[
{
"Id": "02e048310a4466fe9731c0c2da954c103a3f35cffceb34e5f7331a609f295022",
"Created": "2020-09-01T13:47:54.435939032Z",
"Path": "/bin/bash",
"Args": [
"-c",
"while true;do echo lixuanwen;done"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 26612,
"ExitCode": 0,
"Error": "",
"StartedAt": "2020-09-01T13:47:54.970992813Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:0d120b6ccaa8c5e149176798b3501d4dd1885f961922497cd0abef155c869566",
"ResolvConfPath": "/var/lib/docker/containers/02e048310a4466fe9731c0c2da954c103a3f35cffceb34e5f7331a609f295022/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/02e048310a4466fe9731c0c2da954c103a3f35cffceb34e5f7331a609f295022/hostname",
"HostsPath": "/var/lib/docker/containers/02e048310a4466fe9731c0c2da954c103a3f35cffceb34e5f7331a609f295022/hosts",
"LogPath": "/var/lib/docker/containers/02e048310a4466fe9731c0c2da954c103a3f35cffceb34e5f7331a609f295022/02e048310a4466fe9731c0c2da954c103a3f35cffceb34e5f7331a609f295022-json.log",
"Name": "/intelligent_bhabha",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "docker-default",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"Capabilities": null,
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/f2263e7153fd7d600750ca634b0330632b03193b486daef0e2d330d1619e2d72-init/diff:/var/lib/docker/overlay2/6f44cab3626de40c0c182f97d3b2d7fc98fb87cde61744662ad735cb5b7fd75d/diff",
"MergedDir": "/var/lib/docker/overlay2/f2263e7153fd7d600750ca634b0330632b03193b486daef0e2d330d1619e2d72/merged",
"UpperDir": "/var/lib/docker/overlay2/f2263e7153fd7d600750ca634b0330632b03193b486daef0e2d330d1619e2d72/diff",
"WorkDir": "/var/lib/docker/overlay2/f2263e7153fd7d600750ca634b0330632b03193b486daef0e2d330d1619e2d72/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "02e048310a44",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/bash",
"-c",
"while true;do echo lixuanwen;done"
],
"Image": "centos",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20200809",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS"
}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "cbc4705f3bb6abd96c1b51a38ba120cc9d9800ba5dfd5fa6c22d8e7de72e5a52",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/cbc4705f3bb6",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "86a894c787c151054dd073f74142954d43c30230db5bd0470455797c659e2d7e",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:03",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "c0fa7fbdf9d00de925e0768342bac001427394f71714f799f090f30946b3b9c1",
"EndpointID": "86a894c787c151054dd073f74142954d43c30230db5bd0470455797c659e2d7e",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:03",
"DriverOpts": null
}
}
}
}
]
root@ubuntu18:~#
## 通常容器使用后台方式运行,若需要进入容器,则
# 进入容器方式一 (开启一个新的终端)
docker exec -it 容器id /bin/bash
# 进入容器方式二 (进入容器正在执行的终端)
docker attach 容器ID
docker cp 容器ID:容器内路径 目的主机路径
root@ubuntu18:~# docker ps -a --no-trunc
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ab129318cdec55baf17f2fe8b4fb5308ca6a76cac052d2e8ae11410b4754d944 wordpress "docker-entrypoint.sh apache2-foreground" 36 hours ago Up 36 hours 0.0.0.0:8080->80/tcp MyWordPress
ec87bdac74be1f2fe457d001ab93546c53ff8798d4b1332a8806cb64a2081d7a mariadb "docker-entrypoint.sh mysqld" 36 hours ago Up 36 hours 3306/tcp MyWordPress/mysql,db
root@ubuntu18:~#
# 提交容器成为一个新的镜像
docker commit [可选参数] 容器ID [REPOSITORY[:TAG]]
# 可选参数:
-a string 作者
-m string 镜像信息
# 导出镜像
docker save [images] [images] > [name.tar]
或者
docker save -o [name.tar] [images] [images]
# 加载镜像
docker load -i [name.tar]
#获取类型为Deployment的资源列表
kubectl get deployments
#获取类型为Pod的资源列表
kubectl get pods
#获取类型为Node的资源列表
kubectl get nodes
在命令后增加 -A 或 --all-namespaces 可查看所有 名称空间中 的对象,使用参数 -n 可查看指定名称空间的对象,例如
# 查看所有名称空间的 Deployment
kubectl get deployments -A
kubectl get deployments --all-namespaces
# 查看 kube-system 名称空间的 Deployment
kubectl get deployments -n kube-system
# kubectl describe 资源类型 资源名称
#查看名称为nginx-XXXXXX的Pod的信息
kubectl describe pod nginx-XXXXXX
#查看名称为nginx的Deployment的信息
kubectl describe deployment nginx
# kubectl logs Pod名称
kubectl logs -f nginx-pod-XXXXXXX
# kubectl exec Pod名称 操作命令
# 在名称为nginx-pod-xxxxxx的Pod中运行bash
kubectl exec -it nginx-pod-xxxxxx /bin/bash
指定资源并使用该资源的选择器作为指定端口上新服务的选择器