k8s(五)k8s的HelloWorld
- June 20, 2022
k8s hello
作者:lomtom
个人网站:lomtom.cn 🔗
个人公众号:博思奥园 🔗
你的支持就是我最大的动力。
k8s系列:
使用k8s运行
在K8s部署应用常用方式有以下两种:
- 使用K8s的Yaml文件部署
- 使用helm charts的方式部署
本文将以第一种方式带领大家去完成K8s部署应用的第一个实例。
使用Deployment部署一个Pod
在K8s中,通常是以声明式API来对资源进行控制。这种方式区别于命令式操作,他主要以文件的形式代替了命令的方式。例如Docker、Swarm及大多数软件都是使用的命令式操作。
例如,如果我是用Docker去创建一个nginx,那么我需要拉取镜像,运行容器。
# 拉取镜像
docker pull nginx
# 运行容器
docker run --name mynginx -d -p 8080:80 nginx
使用Swarm
去部署一个nginx
。
docker service create --name mynginx --replicas 1 nginx
而K8s使用声明式API操作,我们只需要将我们需要部署的配置写在一个yaml文件中,然后应用该文件即可,在之后每次的改动、更新等操作,只需要修改该文件即可。
例如,我们需要创建一个nginx服务,那么需要为nginx服务创建一个Deployment
定义文件deploy.yaml
apiVersion: apps/v1
# 控制器类型
kind: Deployment
metadata:
# 控制器名字,全局唯一
name: nginx
labels:
name: nginx
spec:
# Pod 副本的期待数量
replicas: 1
selector:
matchLabels:
app: nginx
#根据此模板创建Pod的副本(实例)
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
# 镜像及版本
image: nginx:1.7.9
ports:
- containerPort: 80
然后使用kubectl create
或者 kubectl apply
命令去创建这个Deployment对象。
# kubectl create
[root@master nginx]# kubectl create -f deploy.yaml
deployment.apps/nginx created
# kubectl apply
[root@master nginx]# kubectl apply -f deploy.yaml
deployment.apps/nginx created
稍等片刻,K8s就会创建两个资源:一个Deployment,一个Pod。
[root@master nginx]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 1/1 1 1 1m
[root@master nginx]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-5d59d67564-qhmcm 1/1 Running 0 1m
应用被创建出来了,那么这中间到底发生了什么事情呢?
首先,可以看到这个API对象中指定了Kind
为Deployment
,在k8s(三)走进k8s中提及,Deployment
是一个多副本控制器,他会控制副本控制器来完成Pod的创建。
然后,可以查看spec.replicas
参数,其数值为一,那么Deployment
会相应的创建一个副本控制器。我们可以使用kubectl get rs
来进行查看,如果不懂Deployment
与ReplicatSet
的关系也不要紧,后续会着重介绍到。
[root@master nginx]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-5d59d67564 1 1 1 35m
如果说我们需要两个完全相同的两个副本,并且以负载均衡的方式共同对外提供服务。那么只需要修改yaml文件中副本的数量即可。即:
spec:
replicas: 2
接下来,可以着重关注spc.template
参数,这里定义了一个Pod的模板信息,其中的spc.containers
描述了这个Pod中容器信息,包括容器的镜像、名称、监听的端口号等信息。这里制定了一个名称为nginx
的氢气,镜像指定为nginx:1.7.9
,并且监听80端口。
在这里我们可以很清晰的看到,spc.template
参数描述的就是一个Pod的信息,所以K8s中的一个Pod其实就是K8s中管理与部署的最小单元,并且一个Pod中通常可以有多个容器,你再回过头去看之前(k8s(三)走进k8s)的概念是不是又懂了很多呢。
如果是私有仓库的镜像,或者想要优先从私有仓库拉取的话需要加imagePullPolicy
参数,只从私有仓库拉取就设为Never
,优先从私有仓库拉取设为IfNotPresent
。因为默认是拉去远程的,需要修改配置,在RC定义文件中设置为优先拉取本地或只拉取本地,或者检查该pod所部署的节点有没有进行仓库的授权操作。
imagePullPolicy: IfNotPresent
或
imagePullPolicy: Never
完整:
apiVersion: apps/v1
# 控制器类型
kind: Deployment
metadata:
# 控制器名字,全局唯一
name: nginx
labels:
name: nginx
spec:
# Pod 副本的期待数量
replicas: 1
selector:
matchLabels:
app: nginx
#根据此模板创建Pod的副本(实例)
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
# 镜像及版本
image: nginx:1.7.9
#注意自己的镜像要设置不要去公有仓库拉取,否则会失败
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
使用Service对外暴露服务
单单部署一个应用往往是不够的,一些特殊的应用,往往是需要对外暴露并且能够访问的,那么在K8s中,这又是怎么做到的呢?
如果想要让Pod对外暴露服务,需要定义一个Service,名为svc.yaml
,其内容为:
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
type: ClusterIP
selector:
app: nginx
随后,在集群中同样适用kubectl create
或者 kubectl apply
命令去创建这个Service对象。
[root@master service]# kubectl apply -f svc.yaml
service/nginx created
然后,k8s就会创建一个Service并将其与Pod关联起来,接下来,用kubectl命令查看刚刚创建的svc:
[root@master service]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx ClusterIP 10.103.11.225 <none> 80/TCP 2m50s
为了验证这个Service服务是否能正常运行,我们可以使用Curl命令访问一下,即CLUSTER-IP + PORT:
[root@master service]# curl http://10.103.11.225
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
可以看出,服务已经正确对外暴露了,但是目前还是只能在集群内部访问,如果需要在集群外也能够访问的话,那么就需要重新修改svc.yaml的内容了,将其类型改为NodePort
,并且设置对外暴露的端口nodePort
,如果不指定nodePort
也没关系,k8s会随机分配一个可用的端口。
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
nodePort: 30080
type: NodePort
selector:
app: nginx
并且重新更新配置即可:
[root@master service]# kubectl apply -f nginx-svc.yaml
service/nginx configured
[root@master service]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx NodePort 10.103.11.225 <none> 80:30080/TCP 8m31s
那么,我们就可以在集群外使用Master IP + NodePort访问了。
那么,Service是怎么与我们建立的Pod的联系起来的呢?
在上述的配置文件中,我们定义了一个类型为Service的API对象,并且通过标签选择器spc.selector
来选择标签为nginx
的Pod实例,而之前使用Deployment创建的Pod中的标签就是nginx
,参数spc.ports.port
指定的端口就是Pod要进行访问的端口。
随后,kube-proxy
会将对这个Service发送的每一个请求都转发到其对应的Pod上。
那么,问题又来了,我们怎么去访问这个Service呢?
其实每一个Service都会生成一个集群内唯一的虚拟IP,即Cluster IP,这个IP只能在集群内能够访问,并且这个IP在Service整个生命周期内都不会发生改变。然后K8s在集群内部做一个Cluster IP与Service (准确来说是ServiceName)的DNS域名映射,即可将该Cluster IP与这个Service一一对应起来。
然后,当Service类型为ClusterIP时,我们仅能够通过Cluster IP + PORT进行服务的访问,因为Cluster IP 仅仅在集群内访问,所以Cluster IP 类型的svc也只能够在集群内进行访问;当Service类型为NodePort时,我们就能Master IP + NodePort进行服务的访问,他会将NodePort的端口的请求转发到Pod的Port端口。这样,我们就能访问我们部署的服务了。
最后,如果我们不需要这些API资源了,同样可以使用kubectl delete
命令进行删除。
[root@master service]# kubectl delete -f svc.yaml
service "nginx" deleted
[root@master deploy]# kubectl delete -f deploy.yaml
deployment.apps "nginx" deleted
当然,如果我们想一起创建以上两种资源,可以将其配置文件卸载同一个文件内并且以---
进行分隔即可。
以上体验了一下K8s如何部署应用的,相对于传统的部署方式,是不是方便了很多呢。但是,K8s的强大远远不止这些。