MariaDB 与 K8s:容器/Deployment 之间的通信

上一篇博客中,我们从一个 YAML 文件创建了一个后台 Deployment 资源,该资源包含一个作为后台容器的单个容器(MariaDB)。

在本篇博客中,我们将继续创建前端容器,通过 Service 和其他资源与后端进行通信。

关于 Service

通过 Deployment 运行应用程序时,Pod 会被动态创建和销毁。创建后,它们会在集群中获得内部 IP 地址,并且由于它们是短暂的,需要一种稳定的方式来实现 Pod 之间的通信。Service 用于实现此目的。创建后,K8s 会为 Service 名称分配集群 IP。

可以使用 kubectl expose 命令暴露 Deployment 资源来创建 Service。我们将 Deployment 作为 Service 在端口 3306 上暴露。这将创建一个 ClusterIP 类型的 Service(默认类型),该 Service 在集群内部可达。如果 Service 需要在集群外部可达,可以使用 NodePort 类型(更多关于 Service 类型的信息)。Service 的名称将与资源的名称相同。

$ kubectl expose deployment/mariadb-deployment --port 3306
service/mariadb-deployment exposed

要检查 Service,运行 kubectl get service mariadb-deployment

$ kubectl get svc mariadb-deployment
NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
mariadb-deployment   ClusterIP   10.103.111.200   <none>        3306/TCP   76s
    

要获取更多关于 Service 的信息,运行 kubectl describe service 命令

Name:              mariadb-deployment
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=mariadb
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.103.111.200
IPs:               10.103.111.200
Port:              <unset>  3306/TCP
TargetPort:        3306/TCP
Endpoints:         172.17.0.12:3306,172.17.0.4:3306
Session Affinity:  None
Events:            <none>

请注意,Endpoints 与 Pod IP 相关。TargetPort 指的是 Service 需要连接的容器端口,而 Port 指的是 Service 本身的端口。建议这两个端口相等。

现在我们可以使用 Service 名称(而不是 Pod 名称)来执行 kubectl exec 以测试 mariadb 客户端

$ kubectl exec svc/mariadb-deployment -- mariadb -uroot -psecret -e "select current_user()"
current_user()
root@localhost

要删除 Service,在 kubectl 上运行删除命令

$ kubectl delete svc mariadb-deployment
service "mariadb-deployment" deleted

或者,我们可以使用 YAML 文件创建 Service。我们来创建 Service 文件 mariadb-service.yaml。该文件也可以在 GitHub mariadb.org-tools 上找到。

apiVersion: v1
kind: Service
metadata:
  name: mariadb-internal-service
spec:
  selector:
    app: mariadb
  ports:
    - protocol: TCP
      port: 3306
      targetPort: 3306

请注意,Service 使用 标签和选择器匹配一组 Pod,这些标签和选择器是在创建对象时或之后附加到对象的键值对。要创建 Service,运行 kubectl apply 命令并显示结果。

$ kubectl apply -f mariadb-service.yaml 
service/mariadb-internal-service created
$ kubectl get svc mariadb-internal-service
NAME                       TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
mariadb-internal-service   ClusterIP   10.100.230.139   <none>        3306/TCP   4s

作为练习,尝试运行 kubectl edit svc mariadb-internal-service 并将类型更改为 NodePort。之后,您应该获得一个在集群外部可访问的端口,可以通过 Node IP 地址(使用 minikube ip 获取)后跟获取的 Node 端口来访问。尝试使用 curl $(minikube ip):node_port 获取二进制输出。

创建前端应用程序

作为前端应用程序,我们将使用 phpmyadmin(来自 bitnami),并将其启动到我们在上一篇博客中创建的同一个 Deployment 中的一个新容器中。因此,我们将拥有一个包含 2 个 Pod 的单个 Deployment,并使用上一步中创建的现有 Service。

在继续之前,我们需要创建一个 ConfigMap 资源。ConfigMap 用于存储非机密的键值对,可用作环境变量、命令行参数或 中的配置文件。它们允许创建其他 K8s 对象可以使用的配置。在此示例中,我们将使用 ConfigMap 存储一个 MariaDB Service,并将该数据用作 phpmyadmin 应用程序所需的环境变量 DATABASE_HOST 的值。

ConfigMap 可以在文件中创建。我们将其命名为 mariadb-configmap.yaml(可在 GitHub 上找到)。它如下所示

apiVersion: v1
kind: ConfigMap
metadata:
  name: mariadb-configmap
data:
  database_url: mariadb-internal-service

Data 字段有一个键 database-url,其值是引用上一步中创建的 MariaDB 数据库的 Service 名称。

要创建和显示 ConfigMap 资源,运行

$ kubectl apply -f mariadb-configmap.yaml 
configmap/mariadb-configmap created
$ kubectl get configmap mariadb-configmap
NAME                DATA   AGE
mariadb-configmap   1      41s

尝试运行 kubectl describe configmap mariadb-configmap,您将看到带有键值对的 Data 字段以及一个可选的 BinaryData 字段。

从这里,我们可以将 phpmyadmin 应用程序作为现有 Pod 中的一个容器使用,或者创建其自己的相关 Deployment。建议为 phpmyadmin 应用程序创建一个特定的 Deployment(作为练习),但我在此决定使用第一种方法(拥有一个包含 2 个容器的 Deployment)来展示如何使用多个容器。

我们来更新 mariadb-deployment.yaml 并将其命名为 mariadb-deployment-with-phpmyadmin.yaml(代码可在 GitHub 上找到),该文件将包含 2 个容器。它应该如下所示

apiVersion: apps/v1
kind: Deployment # what to create?
metadata:
  name: mariadb-deployment
spec: # specification for deployment resource
  replicas: 2 # how many replicas of pods we want to create
  selector:
    matchLabels:
      app: mariadb
  template: # blueprint for pods
    metadata:
      labels:
        app: mariadb # service will look for this label
    spec: # specification for Pods
      containers:
      - name: mariadb
        image: mariadb
        ports:
        - containerPort: 3306 
        env:
        - name: MARIADB_ROOT_PASSWORD
          value: secret
      - name: phpmyadmin
        image: bitnami/phpmyadmin:latest
        ports:
        - containerPort: 8080
        env:
        - name: DATABASE_HOST
          valueFrom:
            configMapKeyRef:
              name: mariadb-configmap
              key: database_url

注意,DATABASE_HOST 的值通过我们之前创建的名称和键从 ConfigMap 中引用。我们通过应用文件来启动这个 Deployment,并观察创建的 Deployment 和 Pod 的结果。

$ kubectl apply -f mariadb-deployment-with-phpmyadmin.yaml 
deployment.apps/mariadb-deployment created
$ kubectl get deploy
NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
mariadb-deployment   2/2     2            2           15s
# Check Pods
$ kubectl get pods -l app=mariadb
NAME                                  READY   STATUS    RESTARTS   AGE
mariadb-deployment-6d654f6fdc-8hmcq   2/2     Running   0          3m21s
mariadb-deployment-6d654f6fdc-bx448   2/2     Running   0          3m21s
# Get information about deployment
$ kubectl describe deploy mariadb-deployment

因为我们想要 2 个副本,所以最终得到 2 个 Pod,每个 Pod 运行 2 个容器。要获取每个容器的信息,可以运行 kubectl log <pod-hash> <container-name>

# Logs for MariaDB container
$ kubectl logs mariadb-deployment-6d654f6fdc-8hmcq mariadb
...
2022-03-18 13:52:35 0 [Note] mariadbd: ready for connections.
Version: '10.7.3-MariaDB-1:10.7.3+maria~focal'  socket: '/run/mysqld/mysqld.sock'  port: 3306  mariadb.org binary distribution

# Logs for phpmyadmin container
$ kubectl logs mariadb-deployment-6d654f6fdc-8hmcq phpmyadmin
...
phpmyadmin 13:52:30.20 INFO  ==> Enabling web server application configuration for phpMyAdmin
phpmyadmin 13:52:30.29 INFO  ==> ** phpMyAdmin setup finished! **
phpmyadmin 13:52:30.30 INFO  ==> ** Starting Apache **

通过 kubectl exec,我们可以检查客户端的工作情况

$ kubectl exec mariadb-deployment-6d654f6fdc-8hmcq mariadb -- mariadb -uroot -panel -e "select version()"
Defaulted container "mariadb" out of: mariadb, phpmyadmin
version()
10.7.3-MariaDB-1:10.7.3+maria~focal

要测试前端,我们必须创建 Service 将端口暴露给 phpmyadmin 应用程序。我们通过在上一篇博客中学到的 kubectl expose 命令来完成,并显示结果。

请注意,由于我们有 2 个 Pod,使用的类型是 LoadBalancer。Minikube 支持此类型。描述 Service 时,可以看到 Endpoints,其 IP 是 Pod IP 和 phpmyadmin 容器的端口。

注意使用 -o wide 以宽格式输出。

$ kubectl expose deploy/mariadb-deployment --port 8080 --target-port 8080 --type LoadBalancer --name=phpmyadmin-service
service/phpmyadmin-service exposed

$ kubectl get svc phpmyadmin-service -o wide
NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE    SELECTOR
phpmyadmin-service   LoadBalancer   10.97.244.156   <pending>     8080:31789/TCP   7m7s   app=mariadb

$ kubectl describe svc phpmyadmin-service
Name:                     phpmyadmin-service
Namespace:                default
Labels:                   <none>
Annotations:              <none>
Selector:                 app=mariadb
Type:                     LoadBalancer
IP Family Policy:         SingleStack
IP Families:              IPv4
IP:                       10.97.244.156
IPs:                      10.97.244.156
Port:                     <unset>  8080/TCP
TargetPort:               8080/TCP
NodePort:                 <unset>  31789/TCP
Endpoints:                172.17.0.4:8080,172.17.0.9:8080
Session Affinity:         None
External Traffic Policy:  Cluster
Events:                   <none>

在测试 phpmyadmin 之前,我们先创建一个名为“k8s”的示例数据库

$ kubectl exec mariadb-deployment-6d654f6fdc-8hmcq mariadb -- mariadb -uroot -panel -e "create database if not exists k8s; show databases;"
Defaulted container "mariadb" out of: mariadb, phpmyadmin
Database
information_schema
k8s
mysql
performance_schema
sys

要测试 phpmyadmin-service,运行 curl $(minikube ip):31789,或者在浏览器中打开 Service

$ minikube service phpmyadmin-service
|-----------|--------------------|-------------|---------------------------|
| NAMESPACE |        NAME        | TARGET PORT |            URL            |
|-----------|--------------------|-------------|---------------------------|
| default   | phpmyadmin-service |        8080 | http://192.168.49.2:31789 |
|-----------|--------------------|-------------|---------------------------|

Minikube 将打开浏览器,通过 K8s 使用内部 MariaDB Service 连接到 MariaDB 服务器(注意之前创建的“k8s”数据库)。

最后,我们可以创建一个包含我们所需所有 K8s 资源(ConfigMap、2 个 Service 和 Deployment)的单个文件。这已在 GitHub 上完成。

结论和未来工作

在本篇博客中,我们了解了新的 K8s 资源,即 Service 和 ConfigMap,它们的属性以及如何使用它们在容器之间进行交互。作为一项不错的练习,您可以扩展本教程,创建一个前端 Deployment 而不是前端容器,以便与后端 Deployment 进行交互。

在下一篇博客中,我们将学习 Secret,一个用于隐藏应用程序代码中机密数据的 K8s 对象,以及 Statefulset,一个有助于在 K8s 集群中保持数据一致性的 K8s 资源。

欢迎在 Zulip 上讨论。

阅读更多