由于在工作中使用了 K8s
并且深刻体会到了他带来的便利即好处,但是 K8s
学习还是有一定的门槛。
而且在平常自己做一些开源项目时,或者自己做一些小的服务,由于 K8s
本身需要的 CPU 和内存较高,大部分薅羊毛买的云主机根本没法使用。
于是笔者打算写一个系列的 K8s
上手教程分享给大家,并且分享一下 K8s
怎么用在我们平常做开源项目部署服务。
首先我们想要在我们的云主机上用上 K8s
自然先要搭建环境,但是这次我们不会直接搭建 K8s
环境,而是使用 K3s
。
如果对 K8s
搭建感兴趣的同学可以看我之前的博文 「K8s 学习日记」Kubeadm 部署 kubernetes 集群,当然在生产环境中还是推荐大家使用托管的 K8s。
有的同学可能就会问了,不是讲 K8s
吗 ?为什么又来一个 K3s
?
这里就给大家简单说一下,因为搭建 本身较为繁琐,而且要求云主机的配置还比较高,当你把 K8s
搭建完成后你会发现服务器的 CPU 和内存基本上以及不足以让你部署服务了。
所以如果打算在平常我们薅羊毛买的云主机上使用使用 K8s
或是体验 K8s
的功能,更推荐大家使用 K3s。
关于 K3s
和 K8s
的区别笔者就不在这里介绍了,有兴趣的同学可以自行 Google。大家只要知道 K3s
在使用上跟 K8s
并无太大差异,当然使用时有什么疑惑可以查阅 K8s
的文档,而且足够满足我们在平常自己做小的开源项目部署服务使用,这也是笔者的使用感受。
废话不多说我们直接开始,笔者的云主机是的操作系统是 CentOS 7
,安装 K3s
只需要用他的官方一键安装脚本非常便捷。(官方文档)
国内的云主机:
curl -sfL http://rancher-mirror.cnrancher.com/k3s/k3s-install.sh | INSTALL_K3S_MIRROR=cn INSTALL_K3S_EXEC="--tls-san {你的云服务器的 IP 地址}" sh -
国外的云主机:
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--tls-san {你的云服务器的 IP 地址}" sh -
看到如下输出表示安装完成了,是不是非常的简单,笔者在第一次安装时也被 K3s
的安装便捷震惊了。
[INFO] Finding release for channel stable
[INFO] Using v1.18.9+k3s1 as release
[INFO] Downloading hash http://rancher-mirror.cnrancher.com/k3s/v1.18.9-k3s1/sha256sum-amd64.txt
[INFO] Downloading binary http://rancher-mirror.cnrancher.com/k3s/v1.18.9-k3s1/k3s
[INFO] Verifying binary download
[INFO] Installing k3s to /usr/local/bin/k3s
[INFO] Creating /usr/local/bin/kubectl symlink to k3s
[INFO] Creating /usr/local/bin/crictl symlink to k3s
[INFO] Creating /usr/local/bin/ctr symlink to k3s
[INFO] Creating killall script /usr/local/bin/k3s-killall.sh
[INFO] Creating uninstall script /usr/local/bin/k3s-uninstall.sh
[INFO] env: Creating environment file /etc/systemd/system/k3s.service.env
[INFO] systemd: Creating service file /etc/systemd/system/k3s.service
[INFO] systemd: Enabling k3s unit
Created symlink from /etc/systemd/system/multi-user.target.wants/k3s.service to /etc/systemd/system/k3s.service.
[INFO] systemd: Starting k3s
输入以下命令就可以知道我们目前 K3s
已经安装完成并且有一个节点。
kubectl get nodes
NAME STATUS ROLES AGE VERSION
instance-qgq0ripc Ready master 66s v1.18.9+k3s1
为了方便后续的使用,直接在自己的电脑上操作,可以在自己的电脑上安装 kubectl
,笔者用的是 Mac
所以这里介绍一下 Mac 如何安装,其他操作系统可以自行 Google,非常容易找到。当然如果不做这一步也可以直接在服务器上使用 kubectl
。
首先安装 kubectl:
brew install kubectl
然后将云主机上的 /etc/rancher/k3s/k3s.yaml
文件拷贝到电脑上的 ~/.kube/config
目录。
最后将 ~/.kube/config
文件中的 server: https://127.0.0.1:6443
修改成 server: https://{你的云服务器的 IP 地址}:6443
。
这样你就可以在你的电脑上使用 kubectl
来访问云服务器的 K3s
集群了。
➜ kubectl get nodes
NAME STATUS ROLES AGE VERSION
instance-qgq0ripc Ready master 5h10m v1.18.9+k3s1
K8s
基础概念和如何部署一个服务在部署服务之前我先来简单讲一下 K8s
中的一些基本概念,他们分别是:
一下说这么多的概念可能不方便记忆,我们通过部署一个服务一步一步的来理解这些资源的作用。
首先 K8s
在容器的基础上引入了一个 Pod 的概念,大家可以将容器理解成一个进程
,Pod 可以理解成一个进程组,这里不做过多的赘述,可以阅读一下我之前的一篇文章 新一代的微服务架构 Service Mesh 的 Part 2「Docker」到 「K8s」 部分。
我这里也直接放一个 Pod
的定义:
apiVersion: v1
kind: Pod
metadata:
name: myapp
labels:
name: myapp
spec:
containers:
- name: myapp
image: <Image>
ports:
- containerPort: <Port>
可以看到它有一个 containers
的属性,是一个 Array
数组,里面是一个容器的定义,包含了:
这几个字段非常容易理解,但是我们一般在使用时不会直接写一个 Pod 的 yaml
定义,而是写一个 Deployment
的定义,主要原因如下:
我们再来看看 Deployment
的定义:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: <Image>
ports:
- containerPort: <Port>
这里就肯定有人会觉得,一下子记这么多的定义和字段好难记。这里教大家一个非常方便的记忆方法,可以注意到 Deployment 中的 template
字段的属性,其实就是一个 Pod 的定义,它也有 containers
、name
、image
、ports
等属性,说白了 template
字段就是用于生成 Pod 的模板。
这里主要注意 Deployment 中的 selector.matchLabels
字段,它是用于 K8s
识别这次部署任务所关联的 Pod,在 Pod 的定义中同样有 app: myapp
的字段,这是一个标签,你可以写成你自己定义的标签, 但是 Pod
中的 labels
必须是 Deployment
的 selector.matchLabels
的子集。
这里说的比较绕,大家就可以理解成,Deployment 通过 selector.matchLabels
去寻找 K8s
中定义的 Pod,但是它怎么知道哪些 Pod 是自己创建的呢,所以 Pod 中也必须定义相应的标签,Deployment 才能找到它。
接下来我先自己动手写一个 Deployment 将一个 nginx 服务部署到 K3s
中。
我们创建一个 nginx.yaml
的文件他的 Deployment 定义非常简单,如下所示:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
然后我们执行如下命令将这个 Deployment 创建到 K3s
中:
➜ kubectl apply -f ./nginx.yaml
deployment.apps/nginx created
我们就可以通过以下命令分别查看集群中创建的 Deployment 和 Pod 的状态:
➜ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 1/1 1 1 3m14s
➜ kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-cc7df4f8f-r9z6d 1/1 Running 0 3m39s
这样就完成了一个服务的部署了,是不是非常简单。如果你想部署自己服务,只需要将 image
修改成你自己的镜像即可,当然 Deployment 中还有其他的字段,这里为了方便大家快速入门,就不会介绍那么多的字段。
服务部署完了,我们应该如何访问它呢?这里就需要用到 Service,我们先来看看 Service 的定义:
kind: Service
apiVersion: v1
metadata:
name: Service Name
spec:
selector:
app: Selector Label
type: NodePort
ports:
- nodePort: 8080
port: 8080
protocol: TCP
targetPort: 80
它的定义也非常简单,很容易观察到它需要定义 port
和 targetPort
用于映射这个服务到目标 Pod 的端口。但是为什么还有一个 nodePort
呢?
这里就要先介绍以下它的 type 字段,它的可选值为 LoadBalancer
、ClusterIP
、NodePort
,一下子引入太多的概念可能会让大家消化不了。所以为了方便记忆,可以理解为 ClusterIP
模式时 Service 无法被外部访问,NodePort
模式时 Service 会在宿主机上映射一个端口供外部访问,LoadBalancer
模式主要时在使用托管的 K8s
中云厂商会提供负载均衡器让 Service 供外部访问。
所以这里我们使用 NodePort
模式,当然如果有感兴趣的同学可以自行 Google,这里也同样不做过多的赘述。
并且注意 Service 中也有一个 selector
字段也是用于关联 Pod,我们将其设置为跟 Pod 的标签相同的值。
我们同样还是在刚刚的 nginx.yaml
文件下定义一个 Service 资源,用三个 “-“ 符号隔开:
# ...
---
kind: Service
apiVersion: v1
metadata:
name: nginx
spec:
selector:
app: nginx
type: NodePort
ports:
- nodePort: 30080
port: 8080
protocol: TCP
targetPort: 80
同样执行 kubectl apply
命令使 Service 生效。
➜ kubectl apply -f ./nginx.yaml
deployment.apps/nginx unchanged
service/nginx created
然后可以通过以下命令观察我们创建的 Service:
➜ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx NodePort 10.43.67.147 <none> 8080:30080/TCP 7m25s
然后我们通过浏览器尝试访问云服务器的 30080
端口,记得在云厂商控制台安全组把这个端口打开。
可以看到成功访问了,就这么简单,将服务。
前面有提到 Namespace 资源,在我们日常使用 K8s
中,因为会创建非常多的 Deployment 或 Service,当这些这些资源过多时,他们的名称可能重复不便于管理,这里我们就使用 Namespace 将他们隔离开。
首先我们先通过以下命令将刚刚创建的资源都删除,通过这样的方式可以方便的删除刚刚部署的 nginx:
➜ kubectl delete -f nginx.yaml
deployment.apps "nginx" deleted
service "nginx" deleted
然后我们在 nginx.yaml
文件的头部定义一个 Namespace 资源,它的名称为 `nginx-1`,并且在 Deployment 和 Service 资源的 metadata
字段添加 namespace
属性,添加后的完整文件定义如下:
apiVersion: v1
kind: Namespace
metadata:
name: nginx-1
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: nginx-1
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
---
kind: Service
apiVersion: v1
metadata:
name: nginx
namespace: nginx-1
spec:
selector:
app: nginx
type: NodePort
ports:
- nodePort: 30080
port: 8080
protocol: TCP
targetPort: 80
然后 apply 一下这个 yaml 文件:
➜ kubectl apply -f nginx.yaml
namespace/nginx-1 created
deployment.apps/nginx created
service/nginx created
通过命令发现我们找不到原来的 Deployment 和 Service:
➜ kubectl get deployment
No resources found.
➜ kubectl get service
No resources found.
原因是我们制定了 Namespace 所以需要加上一个 -n nginx-1
的参数指定 Namespace, 在创建资源未指定 Namespace 时,资源会默认创建在 default
的 Namespace 下。
➜ kubectl get deployment -n nginx-1
NAME READY UP-TO-DATE AVAILABLE AGE
nginx 1/1 1 1 2m58s
➜ kubectl get service -n nginx-1
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx NodePort 10.43.22.154 <none> 8080:30080/TCP 3m6s
以上就是「K8s 快速上手(一)—— 在云主机上部署我的服务」的全部内容,下一章将会介绍如何在部署的服务中使用配置文件或环境变量配置服务,以及如何挂载存储盘。