通过使用Kubernetes学习分布式系统设计模式

我发现了一本名为《分布式系统设计模式》的好书,其中介绍了使用容器的系统架构模式。为了学习Kubernetes,我尝试实现了其中的每个设计模式,现在向大家介绍一下。

建议阅读这本书,因为它是根据作者的论文编写的,并且还有翻译文章可供参考。

本文将介绍设计模式及其示例

在分散系统设计模式中,总体上介绍了两种设计模式。

    • 1台のノード上で複数のコンテナが動作するシングルノードパターン

複数のノード上で実現されるマルチノードパターン

本文将解释以下设计模式及其示例,以及在Kubernetes中的实现示例,这些模式是从单节点模式衍生出来的。

    • サイドカーパターン

ex1. git-sync
ex2. topz

アンバサダパターン

ex1. twemproxy

アダプタパターン

ex1. redis exporter
ex2. mysql-healthcheck

代码库

undefined

侧边摆动模式

sidecar.png

同步git库
ex2. git同步

这是一个使用git-sync工具实现的边车模式的例子。git-sync会定期访问代码库,并将本地代码与最新代码保持同步的工具。

这个例子的结构如下所示。

     +--------+           +--------+
     | client |           | GitHub | html file
     +--------+           +--------+
          |                   |
          | access            | git pull
          |                   |
+---------------------------------------+
|         |                   |         |
|  +-------------+     +-------------+  |
|  |    Nginx    |     |   git-sync  |  |
|  | <Container> |     | <Container> |  |
|  +-------------+     +-------------+  |
|         |                   |         |
|         | mount             | mount   |
|         |                   |         |
|         |  +-------------+  |         |
|         +--| source code |--+         |
|            |  <Voluem>   |            |
|            +-------------+            |
|                 <Pod>                 |
+---------------------------------------+

git-syncが定期的にgitリポジトリへアクセスし、最新のコードを取得します。
取得されたコードはノード上のVolumeへ保存され、git-syncコンテナとメインとなるコンテナ(ここではNginx)からアクセスできるように構築されています。
この構成により、Nginxのコンテナに手を入れなくとも、常に最新のコードをNginxのコンテナから参照できるようになります。

在代码更新后需要重新启动的情况下,git-sync需要添加一些更复杂的配置。

“宣言书”

以下是Manifext文件的实现方式。

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: git-sync
spec:
  replicas: 1
  selector:
    matchLabels:
      app: git-sync
  template:
    metadata:
      labels:
        app: git-sync
    spec:
      containers:
        - name: nginx
          image: nginx:alpine
          ports:
            - containerPort: 80
          volumeMounts:
            - name: git-sync-volume
              mountPath: /usr/share/nginx
        - name: git-sync
          image: gcr.io/google_containers/git-sync:v3.1.1
          volumeMounts:
            - name: git-sync-volume
              mountPath: /sync
          env:
            - name: GIT_SYNC_REPO
              value: https://github.com/reireias/git-sync-example.git
            - name: GIT_SYNC_BRANCH
              value: master
            - name: GIT_SYNC_ROOT
              value: /sync
            - name: GIT_SYNC_DEST
              value: html
      volumes:
        - name: git-sync-volume
          emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: git-sync
  labels:
    app: git-sync
spec:
  selector:
    app: git-sync
  type: NodePort
  ports:
    - port: 80
      targetPort: 80

解说

    • git-syncコンテナとNginxコンテナを持つPodを1台構築するDeploymentが定義されています

 

    • Deployment中のPodの設定では、コードをコンテナ間で共有するためのvolumeを定義しています

 

    • git-syncで最新のコードを取得するリポジトリは、git-syncコンテナの環境変数で指定しています

もし、自分で起動して確認する場合は、自分でpush可能なリポジトリを指定するために、上記リポジトリをforkし、そのリポジトリを利用してください

Nginxのコンテナを外部へ公開するための、Serviceを定義しています

在minikube上执行

这是在Miniube上的执行示例。

# デプロイする
kubectl apply -f git-sync.yml

# ブラウザでgit-syncサービス(Nginx)へアクセスする
minikube service git-sync

# git-syncで参照しているリポジトリのコードを更新する

# サイドブラウザでアクセスし、htmlファイル等が更新されていることを確認する

顶级

第二个侧边栏模式的例子是使用topz进行资源监视。

構成如下所示。

+---------------------------------------------+
|  +---------------------------------------+  |
|  |  +-------------+     +-------------+  |  |
|  |  |    Nginx    |     |     topz    |  |  |
|  |  | <Container> |     | <Container> |  |  |
|  |  +-------------+     +-------------+  |  |
|  |            <PID namespace>            |  |
|  +---------------------------------------+  |
|                    <Pod>                    |
+---------------------------------------------+
    • topzコンテナとNginxコンテナ間でPID namespaceを共有させています

 

    • topzからNginxのプロセス情報が参照できるようになっています

 

    これをwebアクセスで参照できるのがtopzの機能です

宣言

以下是Manifest文件的实现方式。

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: topz
spec:
  replicas: 1
  selector:
    matchLabels:
      app: topz
  template:
    metadata:
      labels:
        app: topz
    spec:
      shareProcessNamespace: true
      containers:
        - name: nginx
          image: nginx:alpine
          ports:
            - containerPort: 80
        - name: topz
          image: brendanburns/topz:db0fa58
          ports:
            - containerPort: 8080
          command:
            - /server
          args:
            - -addr
            - 0.0.0.0:8080
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  selector:
    app: topz
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
      name: nginx
---
apiVersion: v1
kind: Service
metadata:
  name: topz
  labels:
    app: topz
spec:
  selector:
    app: topz
  type: NodePort
  ports:
    - port: 8080
      targetPort: 8080
      name: topz

解释

    • DeploymentでNginxとtopzコンテナを持つPodを定義しています

 

    外部からアクセスできるように、topzとNginxのそれぞれのServeceを定義しています

在Minikube上执行

# デプロイします
kubectl apply -f topz.yml

# サービス一覧からエンドポイントを確認できます
minikube service list
|-------------|----------------------|-----------------------------|
|  NAMESPACE  |         NAME         |             URL             |
|-------------|----------------------|-----------------------------|
| default     | nginx                | http://192.168.39.196:31831 |
| default     | topz                 | http://192.168.39.196:30532 |
|-------------|----------------------|-----------------------------|

# 下記コマンドでNginxサービスへアクセスできます
minikube service nginx

# topz側のエンドポイントは下記コマンドで表示できるので、ブラウザでアクセスします
echo "$(minikube service topz --url)/topz"
# リソース使用状況が表示されるはずです

大使模式

ambassador.png

例1:twemproxy

twemproxy可以理解成twem代理。

这是一个使用twemproxy作为Redis代理服务器的示例。

结构如下所示。

                     +-----------------+
                     | +-------------+ |
                     | |    Nginx    | |
                     | | <Container> | |
                     | +-------------+ |
                     |        |        |
                     | +-------------+ |
                     | |  twemproxy  | |
                     | | <Container> | |
                     | +-------------+ |
                     |        |  <Pod> |
                     +-----------------+
                              |
            +-----------------+-----------------+ 
            |                 |                 |
  +---------+-----------------+-----------------+---------+
  |         |                 |                 |         |
  | +---------------+ +---------------+ +---------------+ |
  | | Redis Shard 0 | | Redis Shard 1 | | Redis Shard 2 | |
  | |     <Pod>     | |     <Pod>     | |     <Pod>     | |
  | +---------------+ +---------------+ +---------------+ |
  |                     <StatefulSet>                     |
  +-------------------------------------------------------+
    • twemproxyは高速かつ軽量なmemcached/Redis用プロキシです

 

    • リクエスト中のキーに応じて接続先のRedisサーバーを自動的に選択してくれます

 

    • ハッシュを利用しているので、同じキーの保存/取得リクエストはすべて同じRedisサーバーへ送られます

 

    この仕組みにより、Redisサーバーの負荷の分散が実現できます。

宣言书

以下是我们的宣言。

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: sharded-redis
spec:
  selector:
    matchLabels:
      app: redis
  serviceName: "redis"
  replicas: 3
  template:
    metadata:
      labels:
        app: redis
    spec:
      terminationGracePeriodSeconds: 10
      containers:
        - name: redis
          image: redis
          ports:
            - containerPort: 6379
              name: redis
---
apiVersion: v1
kind: Service
metadata:
  name: redis
  labels:
    app: redis
spec:
  ports:
    - port: 6379
      name: redis
  clusterIP: None
  selector:
    app: redis
---
apiVersion: v1
kind: Pod
metadata:
  name: ambassador-example
spec:
  containers:
    - name: nginx
      image: nginx
    - name: twemproxy
      image: ganomede/twemproxy
      command:
        - "nutcracker"
        - "-c"
        - "/etc/config/nutcracker.yml"
        - "-v"
        - "7"
        - "-s"
        - "6222"
      volumeMounts:
        - name: config-volume
          mountPath: /etc/config
  volumes:
    - name: config-volume
      configMap:
        name: twem-config

讲解

    • StatefulSetにて、Redisコンテナを3台定義しています

 

    • DeploymentにてNginxとtwemproxyコンテナをもつPodを定義しています

 

    • 下記に記載してあるtwemproxy用の設定ファイルを参照できるようにconfigMapとそのマウントを定義しています

 

    nginxコンテナからは同一Pod上にtwemproxyコンテナが存在するので、127.0.0.1:6379でtwemproxyに接続ができます

在事前将配置文件注册到configMap中,twemproxy的配置文件如下所示。

redis:
  listen: 127.0.0.1:6379
  hash: fnv1a_64
  distribution: ketama
  auto_eject_hosts: true
  redis: true
  timeout: 400
  server_retry_timeout: 2000
  server_failure_limit: 1
  servers:
   - sharded-redis-0.redis:6379:1
   - sharded-redis-1.redis:6379:1
   - sharded-redis-2.redis:6379:1

在Minikube上运行

# 最初にconfigMapにtwemproxy用の設定ファイルを登録します
kubectl create configmap twem-config --from-file=./nutcracker.yml

# デプロイします
kubectl apply -f twemproxy.yml

# redisクライアントでの動作確認
# nginxコンテナでbashを起動します
kubectl exec -it ambassador-example --container nginx bash 
# redis-cliをインストールします
apt update
apt install -y redis-tools

# twemproxy経由で値をRedisに格納します
redis-cli
127.0.0.1:6379> set hoge 1
127.0.0.1:6379> set fuga 2

# twemproxy経由で値を取得します
127.0.0.1:6379> get hoge

# ローカルマシンに戻り、下記の各コマンドで、各Redisの登録されたキーを確認できます
kubectl exec -it sharded-redis-0 --container redis redis-cli
127.0.0.1:6379> keys *
kubectl exec -it sharded-redis-1 --container redis redis-cli
127.0.0.1:6379> keys *
kubectl exec -it sharded-redis-2 --container redis redis-cli
127.0.0.1:6379> keys *

适配器模式

adapter.png

例1:Redis导出器

这是一种使用redis_exporter来为监控工具Prometheus提供接口的模式。

结构如下:

    +------------+        +-------+
    | Prometheus |        |  app  |
    +------------+        +-------+
          | get metrics       |
+---------+----------------------------+
|         |                   |        |
| +----------------+   +-------------+ |
| | redis_exporter |---|    redis    | |
| |   <Container>  |   | <Container> | |
| +----------------+   +-------------+ |
|                <Pod>                 |
+--------------------------------------+
    RedisはPrometheus用リソース監視I/Fは持っていませんが、この構成で提供できます

宣言

下面是宣言的内容。

---
apiVersion: v1
kind: Pod
metadata:
  name: adapter-example
  namespace: default
  labels:
    app: exporter
spec:
  containers:
    - name: redis
      image: redis
    - name: exporter
      image: oliver006/redis_exporter
      ports:
        - containerPort: 9121
---
apiVersion: v1
kind: Service
metadata:
  name: exporter
  labels:
    app: exporter
spec:
  selector:
    app: exporter
  type: NodePort
  ports:
    - port: 9121
      targetPort: 9121

说明

    • Pod内にRedisコンテナとredis_exporterコンテナを定義しています

 

    Serviceでredis_exporterを外部に公開しています

在Minikube上执行

# デプロイします
kubectl apply -f redis-with-exporter.yml

# 下記コマンドで、Prometheus用I/Fにアクセスし、メトリクスが取得できることを確認します
curl $(minikube service exporter --url)/metrics

MySQL丰富的健康检查

這是使用 Golang 創建的豐富 MySQL 健康檢查工具的適配器模式。

构成如下:

                             +--------+
                             | Client |
                             +--------+
                                  |
                                  | access to "/"
                                  |
+---------------------------------------------+
|                                 |           |
| +-------------+       +-------------------+ |
| |    MySQL    | query | mysql-healthcheck | |
| | <Container> |-------|    <Container>    | |
| +-------------+       +-------------------+ |
|                    <Pod>                    |
+---------------------------------------------+

reireias/mysql-healthcheckを利用して、MySQLに特定のクエリを発行してヘルスチェックを行います
mysql-healthcheckコンテナへアクセスがあった際にクエリは発行されます

声明

宣言书将如下所示。 shū .)

---
apiVersion: v1
kind: Service
metadata:
  name: healthcheck
spec:
  type: NodePort
  ports:
    - name: healthcheck
      port: 8080
      targetPort: 8080
  selector:
    app: mysql
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:5.6
          env:
            - name: MYSQL_ROOT_PASSWORD
              value: password
            - name: MYSQL_USER
              value: user
            - name: MYSQL_PASSWORD
              value: password
            - name: MYSQL_DATABASE
              value: test
          ports:
            - name: mysql
              containerPort: 3306
          volumeMounts:
            - name: mysql-persistent-storage
              mountPath: /var/lib/mysql
        - name: healthcheck
          image: reireias/mysql-healthcheck
          env:
            - name: MYSQL_USER
              value: user
            - name: MYSQL_PASSWORD
              value: password
            - name: MYSQL_DATABASE
              value: test
            - name: MYSQL_QUERY
              value: 'show databases;'
            - name: MYSQL_HOST
              value: mysql
            - name: MYSQL_PORT
              value: '3306'
            - name: ADDRESS
              value: 0.0.0.0:8080
          ports:
            - name: healthcheck
              containerPort: 8080
      volumes:
        - name: mysql-persistent-storage
          persistentVolumeClaim:
            claimName: mysql-pv-claim
---
kind: PersistentVolume
apiVersion: v1
metadata:
  name: mysql-pv-volume
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 20Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi

解释

    • MySLQコンテナとmysql-healthcheckコンテナをDeploymentで定義しています

 

    • 個々のコンテナの環境変数で設定を指定しています

 

    • mysql-healthcheckをServiceで公開するように定義しています

 

    PersistentVolumeは依存関係で事前に作成するため、別のマニュフェストファイルとして作成しています

在Minikube上执行

# PersistentVolumeをデプロイします
kubectl apply -f mysql-pv.yml

# PodとServiceをデプロイします
kubectl apply -f mysql-with-ritch-healthcheck.yml

# ヘルスチェックが実行されるか確認します
curl $(minikube service healthcheck --url)
# OKと返るはずです

总结

我們一起介紹了一些可以在分散系統中使用的設計模式,並提供了一些單一節點模式的實例。您可能會發現,您已經在許多地方實踐了這些意外的模式,不是嗎?了解設計模式很方便,而且在DockerHub上還有適合的容器供您使用,讓我們充分利用它們吧。

广告
将在 10 秒后关闭
bannerAds