pod介绍
- pod是k8s的最小部署单元
- 是一组容器的集合,即一个pod中可能包含多个容器
- 一个pod中的容器共享网络命令空间
查看容器的网络
其实每次创建一个pod的时候,都会对应的去创建一个网络。
[root@server3 ~]# cat /opt/kubernetes/cfg/kubelet
KUBELET_OPTS="--logtostderr=true \
--v=4 \
--hostname-override=192.168.10.13 \
--kubeconfig=/opt/kubernetes/cfg/kubelet.kubeconfig \
--bootstrap-kubeconfig=/opt/kubernetes/cfg/bootstrap.kubeconfig \
--config=/opt/kubernetes/cfg/kubelet.config \
--cert-dir=/opt/kubernetes/ssl \
--pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0"
其中–pod-infra-container-image=registry.cn-hangzhou.aliyuncs.com/google-containers/pause-amd64:3.0"表示pod创建时创建的网络。
- 然后通过docker ps也可以查看到前面所创建的pod网络。
initcontainers初始化容器
于业务容器开始执行,原先Pod中容器是并行开启,现在进行了改进
Container容器
镜像拉取策略(image PullPolicy)
IfNotPresent:默认值,镜像在宿主机上不存在时才拉取
Always:每次创建Pod都会重新拉取一次镜像
Never:Pod永远不会主动拉取这个镜像
使用以下的命令可以查看并修改到当前使用的控制器拉取镜像的策略
kubectl edit deployment/nginx #在master中操作
……
template:
metadata:
creationTimestamp: null
labels:
run: nginx
spec:
containers:
- image: nginx:latest
imagePullPolicy: Always
name: nginx
ports:
- containerPort: 80
protocol: TCP
……
- 通过以上的指令可以编写yaml文件来是实现pod的创建。
首先编写yaml文件:
[root@localhost demo]# vim pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: Always
command: [ "echo", "SUCCESS" ]
结果:虽然说我们能够成功去创建pod资源,但是这个pod资源一直处于ContainerCreating的状态,并非正常的Running状态。
**原因:**失败的原因是因为命令冲突,其中==command: [ “echo”, “SUCCESS” ]==命令与我们的阿里云镜像相冲突,所以会失败。
**解决:**删除掉冲突的命令行,并且制定需要安装的镜像为nginx:1.14
kubectl delete -f pod1.yaml #删除之前通过pod1.yaml文件创建的pod资源
vim pod1.yaml # 修改yaml文件
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: nginx
image: nginx:1.14
imagePullPolicy: Always
kubectl apply -f pod1.yaml # 更新资源
kubectl get pods # 查看pod资源
NAME READY STATUS RESTARTS AGE
mypod 1/1 Running 0 3s
然后我们可以通过 -o wide来查看到此时pod运行的容器的IP地址。
kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mypod 1/1 Running 0 12s 172.17.79.7 192.168.10.14 <none> <none>
因为现在pod中的容器的服务并没有发布,所以想直接通过web访问时不行的,但是我们可以通过node节点来访问。
[root@server3 ~]# curl -I 172.17.79.7
HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Mon, 08 Mar 2021 07:05:31 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 04 Dec 2018 14:44:49 GMT
Connection: keep-alive
ETag: "5c0692e1-264"
Accept-Ranges: bytes
k8s私有仓库的创建
首先在初始化的状态下下载安装docker服务,前面有说到。
在安装完成的docker的主机中安装harbor。其中需要的组件由docker-compose与harbor-offline-installer-v1.2.2.tgz。其中docker-compose为一个二进制的可执行的包,而harbor-offline-installer-v1.2.2.tgz为一个压缩包。
cp docker-compose /usr/local/bin
chmod +x /usr/local/bin/docker-compose
tar zxvf harbor-offline-installer-v1.2.2.tgz -C /usr/local
cd /usr/local/harbor/
[root@localhost harbor]# ls
common harbor_1_1_0_template LICENSE
docker-compose.clair.yml harbor.cfg NOTICE
docker-compose.notary.yml harbor.v1.2.2.tar.gz prepare
docker-compose.yml install.sh upgrade
- 首先先对harbor的配置文件进行修改
vim harbor.cfg
hostname = 192.168.10.20 # 需要将IP修改为自己的harbor仓库的IP地址
harbor_admin_password = Harbor12345 # 不需要改动,但是后面登录harbor的时候需要使用到
- 运行install.sh脚本文件
[root@localhost harbor]# ./install.sh
[Step 0]: checking installation environment ...
Note: docker version: 20.10.5
Note: docker-compose version: 1.27.4
[Step 1]: loading Harbor images ...
Loaded image: vmware/harbor-ui:v1.2.2
Loaded image: vmware/notary-photon:server-0.5.0
Loaded image: vmware/nginx-photon:1.11.13
Loaded image: vmware/registry:2.6.2-photon
Loaded image: photon:1.0
Loaded image: vmware/notary-photon:signer-0.5.0
Loaded image: vmware/harbor-adminserver:v1.2.2
Loaded image: vmware/harbor-log:v1.2.2
Loaded image: vmware/harbor-db:v1.2.2
Loaded image: vmware/harbor-jobservice:v1.2.2
Loaded image: vmware/harbor-notary-db:mariadb-10.1.10
Loaded image: vmware/clair:v2.0.1-photon
Loaded image: vmware/postgresql:9.6.4-photon
[Step 2]: preparing environment ...
Clearing the configuration file: ./common/config/adminserver/env
Clearing the configuration file: ./common/config/ui/env
Clearing the configuration file: ./common/config/ui/app.conf
Clearing the configuration file: ./common/config/ui/private_key.pem
Clearing the configuration file: ./common/config/db/env
Clearing the configuration file: ./common/config/jobservice/env
Clearing the configuration file: ./common/config/jobservice/app.conf
Clearing the configuration file: ./common/config/registry/config.yml
Clearing the configuration file: ./common/config/registry/root.crt
Clearing the configuration file: ./common/config/nginx/nginx.conf
loaded secret from file: /data/secretkey
Generated configuration file: ./common/config/nginx/nginx.conf
Generated configuration file: ./common/config/adminserver/env
Generated configuration file: ./common/config/ui/env
Generated configuration file: ./common/config/registry/config.yml
Generated configuration file: ./common/config/db/env
Generated configuration file: ./common/config/jobservice/env
Generated configuration file: ./common/config/jobservice/app.conf
Generated configuration file: ./common/config/ui/app.conf
Generated certificate, key file: ./common/config/ui/private_key.pem, cert file: ./common/config/registry/root.crt
The configuration files are ready, please use docker-compose to start the service.
[Step 3]: checking existing instance of Harbor ...
[Step 4]: starting Harbor ...
Creating network "harbor_harbor" with the default driver
Creating harbor-log ... done
Creating harbor-adminserver ... done
Creating harbor-db ... done
Creating registry ... done
Creating harbor-ui ... done
Creating harbor-jobservice ... done
Creating nginx ... done
✔ ----Harbor has been installed and started successfully.----
Now you should be able to visit the admin portal at http://192.168.10.20.
For more details, please visit https://github.com/vmware/harbor .
这样的话harbor仓库就建立好了,此时只要通过harborIP登录到web网页。
上传镜像到私有仓库
node节点保证能够从私有仓库中下载镜像,首先得在配置文件中添加私有仓库的地址(每个节点都要做)。
vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://3m0ss.mirror.aliyuncs.com"],
"insecure-registries":["192.168.10.20"]
}
==注意:==第一行后面一定要有**(,)**,下面的地址是harbor仓库的IP地址
- 首先在我们的node节点通过docker login登录到harbor仓库
- 通过docker pull从公共仓库下载镜像到本地;
- 将刚下下载下来的镜像打上标签
- 将刚才打有标签的镜像上传到私有仓库
- 然后通过web网页登录到私有仓库,可以看到刚才上传的镜像。
私有仓库的问题
上面我们成功进行docker私有仓库的建立,但是当在其他的节点去私有仓库下载的时候发现无法下载,所以需要去解决这问题。
[root@localhost ~]# docker pull 192.168.10.20/project/tomcat
Using default tag: latest
Error response from daemon: pull access denied for 192.168.10.20/project/tomcat, repository does not exist or may require 'docker login': denied: requested access to the resource is denied
并且即使有node节点上面已经拉取了镜像资源,但是在使用该镜像资源创建pod的后,仍然会显示镜像拉取失败的提示信息。
pod资源控制
官方网站:
https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/
Pod和Container的资源请求和限制:
spec.containers[].resources.limits.cpu //cpu上限
spec.containers[].resources.limits.memory //内存上限
spec.containers[].resources.requests.cpu //创建时分配的基本CPU资源
spec.containers[].resources.requests.memory //创建时分配的基本内存资源
示例:
[root@server1 demo]# cat pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: db
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "password"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: wp
image: wordpress
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
**解析:**其中有db和wp两个数据库,每个创建时的基本CPU都是25%,基本内存资源都是64M。每个最大的CPU都是50%,最大内存都是128M。
- 通过yaml文件创建pod资源。
## 方式一
kubectl apply -f pod1.yaml
## 方式二
kubectl create -f pod1.yaml
- 查看具体事件
kubectl describe pod frontend
kubectl describe nodes 192.168.10.14
可以看见之前设置的资源控制已经生效。
所以由资源控制生成的pod资源完成。
查看名称空间
[root@server1 demo]# kubectl get ns
NAME STATUS AGE
default Active 3d2h
kube-node-lease Active 3d2h
kube-public Active 3d2h
kube-system Active 3d2h
重启策略
当Pod在遇见故障之后重启的动作(k8s中不支持重启Pod资源,只有删除重建)
- Always:当容器终止退出后,总是重启容器,默认策略
- OnFailure:当容器异常退出(退出状态码非0)时,重启容器
- Never:当容器终止退出,从不重启容器。
查看当前控制器的重启策略
kubectl edit deploy· #首先得确保目前有控制器在运行,即使用get deployment能够查询到控制器
模拟Always重启策略
[root@server1 demo]# cat pod2.yaml
apiVersion: v1
kind: Pod
metadata:
name: foo
spec:
containers:
- name: busybox
image: busybox
args:
- /bin/sh
- -c
- sleep 30; exit 3
kubectl apply -f pod2.yaml #根据yaml文件创建pod
可以查看到pod一直在重启这样的容器,因为本身默认的重启机制是Always,所以一旦出现终止退出后总是在重启。
模拟Never重启策略
根据之前的定义,就是说容器终止后,pod不会去重启容器。
[root@server1 demo]# cat pod2.yaml
apiVersion: v1
kind: Pod
metadata:
name: foo
spec:
containers:
- name: busybox
image: busybox
args:
- /bin/sh
- -c
- sleep 10
restartPolicy: Never
[root@server1 demo]# kubectl delete -f pod2.yaml
pod "foo" deleted
可以发现与前面不同的是,容器在退出后,pod不会再去重启容器资源,因为正常退出后,重启策略为Never,所以不会再去重启。
探针(Probe)
pod的健康检查
Probe探针的规则
livenessProbe
- 用于判断Container是否处于运行状态
- 当服务crash或者死锁等情况发生时,kubelet会kill掉Container,然后根据其设置的restart policy进行相应操作
ReadinessProbe
- 用于判断服务是否已经正常工作
- 如果服务没有加载完成或工作异常,服务所在的Pod的IP地址会从服务的Endpoints中被移除,也就是说,当服务没有ready时,会将其从服务的load balancer中移除,不会再接受或响应任何请求。
两种规则并无冲突,可以同时进行使用。
Probe探针检查方法
- httpGet 发送http请求,返回200-400范围状态码为成功。
- exec 执行Shell命令返回状态码是0为成功。
- tcpSocket 发起TCP Socket建立成功
示例
exec方式
使用livenessProbe规则搭配exec检查方法进行pod的健康检查。
vim pod3.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-exec
spec:
containers:
- name: liveness
image: busybox
args:
- /bin/sh
- -c
- touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
通过get pods指令可以持续查看到liveness-exec资源会处在一直的运行和关闭状态,因为默认规则为always,所以当创建的文件被删除之后,会触发livenessProbe探针规则,进行不停的重启操作。
调度约束
Kubernetes通过watch的机制进行每个组件的协作,每个组件之间的设计实现了解耦。
调度约束的步骤(理解)
组件
- API Server:作为集群内部和运维人员的唯一交互入口(即所有的指令首先得到达该组件)
- etcd:所有数据的存储以及操作记录都在etcd中进行存储
- Scheduler:为Pod提供调度服务
- Kubelet:处理Master节点下发到本节点的任务,管理Pod和其中的容器
- Docker:创建容器
过程
- 运维人员向k8s平台发送创建pod的请求,API Server将创建该资源的属性信息写入到etcd群集中;
- API Server通过watch机制向Scheduler调度器发送请求分配后台node的相关信息,Scheduler调度器通过评估后台node节点的性能,选出适合建立pod的node节点(假设为node01)进行绑定,然后将这样绑定的网络信息反馈到API Server,API Server将网络信息写到etcd中;
- API Server会通过watch机制向node01节点的Kubelet进行通知,kubelet会触发容器命令,进行容器的创建。创建后,docker会反馈一条状态信息,最终反馈到API Server,API Server会将最终的状态信息写入到etcd中。
调度方式
- 直接调度:nodeName用于将Pod调度到指定的Node名称上(跳过调度器直接分配)
- **选择器:**nodeSelector用于将Pod调度到匹配Label的Node上
直接调度(nodename)
[root@server1 demo]# cat pod5.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-example
labels:
app: nginx
spec:
nodeName: 192.168.10.14
containers:
- name: nginx
image: nginx:1.15
通过 kubectl describe pod [pod name] 来查看pod创建的状态,可以看到未经过Scheduler调度器。
选择器(nodeSelector)
在设置选择器的调度算法之前,首先得对我们后台的node节点进行打标签。
① 打标签
[root@server1 demo]# kubectl label nodes 192.168.10.13 ID=hz
node/192.168.10.13 labeled
[root@server1 demo]# kubectl label nodes 192.168.10.14 ID=sh
node/192.168.10.14 labeled
通过以下命令可以查看到各节点被打上的标签信息:
kubectl get nodes --show-labels
② 编写选择器调度yaml文件
[root@server1 demo]# cat pod6.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-example
labels:
app: nginx
spec:
nodeSelector:
ID: sh
containers:
- name: nginx
image: nginx:1.15
其中也可以明显的查看到不进经过了调度器,并且调度器将资源直接分配到后台的192.168.10.14节点,也就是我们在编写yaml脚本的时候中指定的ID=sh的标签的节点。
说明nodeSelector调度成功。
配置管理
配置管理可以再创建pod时将加密数据存放在pod运行的etcd中。
其次还可以让pod容器以挂载volume的方式访问到挂载在pod指定的路径下。
Secret
用于加密存放在etcd中,创建pod后可以访问
创建凭据
方式一:
将数据传到文件,通过文件来创建凭据。
[root@server1 demo]# echo -n 'admin' > ./username.txt
[root@server1 demo]# echo -n 'asdjdjsioc' > ./password.txt
[root@server1 demo]# ls
password.txt username.txt
[root@server1 demo]# kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt
secret/db-user-pass created
[root@server1 demo]# kubectl get secret
NAME TYPE DATA AGE
db-user-pass Opaque 2 7s
[root@server1 demo]# kubectl describe secret db-user-pass
Name: db-user-pass
Namespace: default
Labels: <none>
Annotations: <none>
Type: Opaque
Data
====
password.txt: 10 bytes
username.txt: 5 bytes
方式二:
通过yaml文件进行数据的传入。
- 首先将想要传入的参数修改为yaml格式能够识别的64转码。
[root@server1 demo]# echo -n 'admin' | base64
YWRtaW4=
[root@server1 demo]# echo -n 'asdjdjsioc' | base64
YXNkamRqc2lvYw==
vim secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: YXNkamRqc2lvYw==
[root@server1 demo]# kubectl apply -f secret.yaml
secret/mysecret created
[root@server1 demo]# kubectl get secret
NAME TYPE DATA AGE
db-user-pass Opaque 2 11m
default-token-lx6bd kubernetes.io/service-account-token 3 3d14h
mysecret Opaque
[root@server1 demo]# kubectl describe secret mysecret
Name: mysecret
Namespace: default
Labels: <none>
Annotations:
Type: Opaque
Data
====
password: 10 bytes
username: 5 bytes
变量导入
我们在前面将想要传导的数据已经传导secret中,现在怎么讲secret中的变量导入到pod中去。
方式一:
使用secret中的变量导入到pod中。
在编写yaml脚本文件的时候,指定使用secret中的指定pod中的参数。
vim secret-var.yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: nginx
image: nginx
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysecret
key: username
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: mysecret
key: password
kubectl apply -f secret-var.yaml
pod/mypod created
[root@server1 demo]# kubectl get pods
NAME READY STATUS RESTARTS AGE
mypod 1/1 Running 0 9s
[root@server1 demo]# kubectl exec -it mypod bash # 进入到pod中,查看传过来的参数
root@mypod:/# ls
bin docker-entrypoint.d home media proc sbin tmp
boot docker-entrypoint.sh lib mnt root srv usr
dev etc lib64 opt run sys var
root@mypod:/# echo $SECRET_USERNAME
admin
root@mypod:/# echo $SECRET_PASSWORD
asdjdjsioc
方式二:
以volume的形式挂载到pod的某个目录下
通过挂载的形式将前面创建的secret挂载到pod容器中的指定目录下。
vim secret-var.yaml
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: foo
mountPath: "/etc/foo"
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
[root@server1 demo]# kubectl apply -f secret-var.yaml
pod/mypod created
[root@server1 demo]# kubectl get pods
NAME READY STATUS RESTARTS AGE
mypod 1/1 Running 0 16s
[root@server1 demo]# kubectl exec -it mypod bash
root@mypod:/# cd /etc/foo
root@mypod:/etc/foo# ls
password username
root@mypod:/etc/foo# cat password
asdjdjsiocroot@mypod:/etc/foo# cat username
ConfigMap
主要用于不需要加密配置信息的存储和导入。
创建凭据
方式一:kubectl
[root@server1 demo]# cat redis.properties # 编写所要传入的参数
redis.host=127.0.0.1
redis.port=6379
redis.password=123456
[root@server1 demo]# kubectl create configmap redis-config --from-file=redis.properties # 通过redis.properties文件进行configmap资源的创建
configmap/redis-config created
[root@server1 demo]# kubectl get configmap # 查看configmap资源
NAME DATA AGE
redis-config 1 11s
[root@server1 demo]# kubectl describe configmap redis-config # 描述configmap资源的具体信息
Name: redis-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
redis.properties:
----
redis.host=127.0.0.1
redis.port=6379
redis.password=123456
Events: <none>
[root@server1 demo]# cat cm.yaml # 通过前面生成的configmap资源来创建新的pod,并将configmap中的参数传到pod中,显示出来
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: busybox
image: busybox
command: [ "/bin/sh","-c","cat /etc/config/redis.properties" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: redis-config
restartPolicy: Never
[root@server1 demo]# kubectl apply -f cm.yaml # 通过yaml文件来创建pod资源
pod/mypod created
[root@server1 demo]# kubectl get pods
NAME READY STATUS RESTARTS AGE
mypod 0/1 Completed 0 5s
[root@server1 demo]# kubectl logs mypod # 因为我们在新的pod中使用cat命令查看所传进去的参数
redis.host=127.0.0.1
redis.port=6379
redis.password=123456
[root@server1 demo]# vim redis.properties
[root@server1 demo]# cat redis.properties
redis.host=127.0.0.1
redis.port=6379
redis.password=123456
方式二:
变量参数形式
vim myconfig.yaml # 编写yaml文件,将想要传的数据以参数形式传入
apiVersion: v1
kind: ConfigMap
metadata:
name: myconfig
namespace: default
data:
special.level: info
special.type: hello
[root@server1 demo]# kubectl apply -f myconfig.yaml # 通过yaml文件,来生成configmap资源
configmap/myconfig created
vim myconfig-var.yaml # 编写yaml文件,将configmap的资源传入到新的pod中
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: busybox
image: busybox
command: [ "/bin/sh", "-c", "echo $(LEVEL) $(TYPE)" ]
env:
- name: LEVEL
valueFrom:
configMapKeyRef:
name: myconfig
key: special.level
- name: TYPE
valueFrom:
configMapKeyRef:
name: myconfig
key: special.type
restartPolicy: Never
[root@server1 demo]# kubectl apply -f myconfig-var.yaml
pod/mypod created
[root@server1 demo]# kubectl logs mypod # 查看新的pod资源的信息
info hello