<
K8s 快速上手(一) 在云主机上部署我的服务
>
上一篇

新一代的微服务架构 Service Mesh
下一篇

K8s 快速上手 (二) 为服务挂载配置文件和存储盘
Toc
在云主机上用上 K8s (K3s) 部署我的服务

由于在工作中使用了 K8s 并且深刻体会到了他带来的便利即好处,但是 K8s 学习还是有一定的门槛。 而且在平常自己做一些开源项目时,或者自己做一些小的服务,由于 K8s 本身需要的 CPU 和内存较高,大部分薅羊毛买的云主机根本没法使用。

于是笔者打算写一个系列的 K8s 上手教程分享给大家,并且分享一下 K8s 怎么用在我们平常做开源项目部署服务。

环境搭建

首先我们想要在我们的云主机上用上 K8s 自然先要搭建环境,但是这次我们不会直接搭建 K8s 环境,而是使用 K3s

如果对 K8s 搭建感兴趣的同学可以看我之前的博文 「K8s 学习日记」Kubeadm 部署 kubernetes 集群,当然在生产环境中还是推荐大家使用托管的 K8s。

有的同学可能就会问了,不是讲 K8s 吗 ?为什么又来一个 K3s ?

这里就给大家简单说一下,因为搭建 本身较为繁琐,而且要求云主机的配置还比较高,当你把 K8s 搭建完成后你会发现服务器的 CPU 和内存基本上以及不足以让你部署服务了。

所以如果打算在平常我们薅羊毛买的云主机上使用使用 K8s 或是体验 K8s 的功能,更推荐大家使用 K3s。

关于 K3sK8s 的区别笔者就不在这里介绍了,有兴趣的同学可以自行 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 MeshPart 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 的定义,它也有 containersnameimageports 等属性,说白了 template 字段就是用于生成 Pod 的模板。

这里主要注意 Deployment 中的 selector.matchLabels 字段,它是用于 K8s 识别这次部署任务所关联的 Pod,在 Pod 的定义中同样有 app: myapp 的字段,这是一个标签,你可以写成你自己定义的标签, 但是 Pod 中的 labels 必须是 Deploymentselector.matchLabels 的子集。

这里说的比较绕,大家就可以理解成,Deployment 通过 selector.matchLabels 去寻找 K8s 中定义的 Pod,但是它怎么知道哪些 Pod 是自己创建的呢,所以 Pod 中也必须定义相应的标签,Deployment 才能找到它。

接下来我先自己动手写一个 Deployment 将一个 nginx 服务部署到 K3s 中。

定义一个 Deployment 将 Nginx 部署到集群中

我们创建一个 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 来让我们访问 Nginx

服务部署完了,我们应该如何访问它呢?这里就需要用到 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

它的定义也非常简单,很容易观察到它需要定义 porttargetPort 用于映射这个服务到目标 Pod 的端口。但是为什么还有一个 nodePort 呢?

这里就要先介绍以下它的 type 字段,它的可选值为 LoadBalancerClusterIPNodePort,一下子引入太多的概念可能会让大家消化不了。所以为了方便记忆,可以理解为 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 端口,记得在云厂商控制台安全组把这个端口打开。

image1

可以看到成功访问了,就这么简单,将服务。

通过 Namespace 隔离资源

前面有提到 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 快速上手(一)—— 在云主机上部署我的服务」的全部内容,下一章将会介绍如何在部署的服务中使用配置文件或环境变量配置服务,以及如何挂载存储盘。

Top
Foot