序文
知識ポイント
- 評価:エントリーレベル
- AI アシスタントを使用してO&M 作業を支援する方法
- 単一ノードの Zookeeper のインストールと展開
- クラスター モード Zookeeper のインストールと展開
- オープンソース アプリケーションの選択に関する考え方
実際のサーバー構成(アーキテクチャは小規模な本番環境を1:1で再現しており、構成は若干異なります)
CPU名 | IP | CPU | メモリ | システムディスク | データディスク | 使用 |
---|---|---|---|---|---|---|
ks-マスター-0 | 192.168.9.91 | 4 | 8 | 50 | 100 | KubeSphere/k8s-master |
ks-マスター-1 | 192.168.9.92 | 4 | 8 | 50 | 100 | KubeSphere/k8s-master |
ks-マスター-2 | 192.168.9.93 | 4 | 8 | 50 | 100 | KubeSphere/k8s-master |
ks-worker-0 | 192.168.9.95 | 4 | 16 | 50 | 100 | k8s-ワーカー/CI |
ks-worker-1 | 192.168.9.96 | 4 | 16 | 50 | 100 | k8s-ワーカー |
ks-worker-2 | 192.168.9.97 | 4 | 16 | 50 | 100 | k8s-ワーカー |
ストレージ-0 | 192.168.9.81 | 2 | 4 | 50 | 100+ | ElasticSearch/GlusterFS/Ceph/Longhorn/NFS/ |
ストレージ-1 | 192.168.9.82 | 2 | 4 | 50 | 100+ | ElasticSearch/GlusterFS/Ceph/Longhorn |
ストレージ-2 | 192.168.9.83 | 2 | 4 | 50 | 100+ | ElasticSearch/GlusterFS/Ceph/Longhorn |
レジストリ | 192.168.9.80 | 2 | 4 | 50 | 200 | ソナタイプ ネクサス 3 |
合計 | 10 | 32 | 88 | 500 | 1100+ |
実際の戦闘環境にはソフトウェアのバージョン情報が関係します
- OS:openEuler 22.03 LTS SP2 x86_64
- キューブスフィア: 3.3.2
- Kubernetes:v1.24.12
- コンテナ:1.6.4
- グルスターFS:10.0-8
- KubeKey: v3.0.8
- 飼育員:3.8.2
導入
現在、当社の実戦コンテンツは、実際の運用・保守作業において必ず遭遇する場面を再現するシーンシミュレーションの形式を採用しております。
職場に入ったばかりで、クラウドネイティブの運用と保守に慣れていない運用と保守の初心者として、今日は上司が私に難しいタスクを用意してくれました。はい、正しく読みました、難しいです。
高難易度= 2 M 1 D =聞いたことはない、見たこともない、やったこともない、短時間。
ボスが提示したタスク要件は次のように整理されています (私はボスの元の言葉に基づいて理解し、推測し、検索し、整理しました。実際、ボスは一言も話していません)。
- K8s クラスターに単一ノード Zookeeper をデプロイする
- K8s クラスターにクラスター モード Zookeeper を展開する
- 利用シーン:研究開発、テスト(後の段階で本番に直接移行する可能性が高い)
- タスクの納品期間:明日(リーダーは非常に簡単だと考えています)
- コア要件: 使用できる限り (自分で理解する)
断れないし、時間も迫っているし、仕事も重いから、やってみよう、行きましょう!!!
2. 課題実現アイデアの分析
労働者が良い仕事をしたいなら、まず道具を研ぐ必要があります。2M1Dレベルのタスクなので、まずはAI時代の運用保守の3つのボードのうち最初の2つのボードを動かし、問題を解決できるかどうかを確認します。
2軸のみで行ったので3本目は使用しませんでした。
最初のトリック - AI アシスタント
プロンプト ワード:「Zokeerper を K8 にデプロイしたいと思っています。シングルノードとクラスター モードのデプロイメント プランをそれぞれ教えてください。ストレージ クラス glusterfs を使用する必要があり、SVC が必要で、ConfigMap が必要であることに注意してください。動物園.cfg」
重要な注意事項:私は学習が苦手で、AI アシスタントに慣れておらず、プロンプトの言葉がうまく書かれていないため、最終的な効果はあまり良くありません。
上記のプロンプトの単語を入力した後、AI Assistant-3.5 はなんとか大量のテキストを私に返しました。私は表示のためにそのエッセンスだけを取り出しました。
- 単一ノード展開プロファイル (
zookeeper-single.yaml
)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: zookeeper-data
spec:
accessModes:
- ReadWriteOnce
storageClassName: glusterfs
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
name: zookeeper
spec:
selector:
app: zookeeper
ports:
- protocol: TCP
port: 2181
targetPort: 2181
---
apiVersion: v1
kind: ConfigMap
metadata:
name: zookeeper-config
data:
zoo.cfg: |
tickTime=2000
dataDir=/data
clientPort=2181
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: zookeeper
spec:
replicas: 1
selector:
matchLabels:
app: zookeeper
template:
metadata:
labels:
app: zookeeper
spec:
containers:
- name: zookeeper
image: zookeeper:3.7.0
resources:
requests:
cpu: 100m
memory: 1Gi
ports:
- containerPort: 2181
volumeMounts:
- name: zookeeper-data
mountPath: /data
env:
- name: ZOOKEEPER_CONFIG_FILE
value: /opt/zookeeper-3.7.0/conf/zoo.cfg
- name: ZOO_SERVERS
value: "server.1=zookeeper-0.zookeeper.default.svc.cluster.local:2888:3888;2181"
volumes:
- name: zookeeper-data
persistentVolumeClaim:
claimName: zookeeper-data
- name: zookeeper-config
configMap:
name: zookeeper-config
- クラスター モード展開構成ファイル (
zookeeper-cluster.yaml
):
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: zookeeper-data
spec:
accessModes:
- ReadWriteOnce
storageClassName: glusterfs
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Service
metadata:
name: zookeeper
spec:
selector:
app: zookeeper
ports:
- protocol: TCP
port: 2181
targetPort: 2181
---
apiVersion: v1
kind: ConfigMap
metadata:
name: zookeeper-config
data:
zoo.cfg: |
tickTime=2000
dataDir=/data
clientPort=2181
initLimit=5
syncLimit=2
server.1=zookeeper-0.zookeeper.default.svc.cluster.local:2888:3888
server.2=zookeeper-1.zookeeper.default.svc.cluster.local:2888:3888
server.3=zookeeper-2.zookeeper.default.svc.cluster.local:2888:3888
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: zookeeper
spec:
serviceName: zookeeper
replicas: 3
selector:
matchLabels:
app: zookeeper
template:
metadata:
labels:
app: zookeeper
spec:
containers:
- name: zookeeper
image: zookeeper:3.7.0
resources:
requests:
cpu: 100m
memory: 1Gi
ports:
- containerPort: 2181
volumeMounts:
- name: zookeeper-data
mountPath: /data
env:
- name: ZOOKEEPER_CONFIG_FILE
value: /opt/zookeeper-3.7.0/conf/zoo.cfg
volumes:
- name: zookeeper-data
persistentVolumeClaim:
claimName: zookeeper-data
- name: zookeeper-config
configMap:
name: zookeeper-config
内容を分析してみると、少しは理解できたような気がしますが、完全には理解できていません。返された結果のシングルノードモードとクラスタモードの設定ファイルは似ています。結果を分析してみましょう。 、考えてみてください。
- kind のタイプが異なります: シングル ノードはDeployment、クラスター モードはStatefulSetですが、現時点ではこれで問題ないようで、考え方は正しいです。
- Deploymentのコピー数は1、StatefulSetのコピー数は3です。
- クラスターモードはvolumeClaimTemplate を使用しません
- クラスターモードのzoo.cfg設定ファイルには他にもいくつかサーバー設定項目がありますが、 myidの処理は実装されていないようです
AIアシスタントが出した結果が要件を満たしているかを分析するには、K8sやZookeeper関連の知識がある程度蓄積されている必要があり、そうでないと理解することができません。
2 番目のトリック - 検索エンジン
AIアシスタントが登場する前は検索エンジンの運用保守支援において1位でしたが、現在は一時2位に位置しており、再び上位に戻る可能性はないと推測されます(私の個人的なランキングを表しています)意見)。
AIアシスタントの出力結果を読んでみると、全体的な構成や内容はまあまあだと感じますが、細部、特にクラスターモードの展開があまり面白くないような気がします。この文書の 3 番目のサブセクションでそれを検証します。
同時に、image: zookeeper:3.7.0
参照したイメージがDockerHubの公式のものなので、対応するイメージとDockerHub上でコンテナ化デプロイメントを利用する方法が存在するはずであることも分かりました。
これは、新しいインスピレーションと新しい学習方法ももたらし、 Docker のデプロイメントを Kubernetes のデプロイメントに変換する最も簡単かつ直接的な方法でもあります。Docker のデプロイメント コマンド、起動コマンド、および関連パラメータを直接確認してから、そこに直接移動します。 K8上で動作します。
DokcerHub の公式 Web サイトに直接アクセスし、キーワード「zookeeper」で直接検索します。
検索結果のスクリーンショット:
検索結果について考えて分析するだけです。
最高ランクの 2 つの Zookeeper イメージは、ダウンロード量が1 億以上で、それぞれDocker official とBitnamiによって作成されました。
先週最も多くダウンロードされたのは Bitnami の Zookeeper で、1,140,215 ダウンロードで、DockerHub の Zookeeper の 681,115 ダウンロードの 2 倍以上です。
ヒント: Bitnami、私は Bitnami を使い始めたのは 10 年以上前です。彼らが作成したワンクリック展開インストール パッケージは、当時非常に優れたワンクリック展開ミドルウェア ソリューション サービス プロバイダーでした。今では、より包括的で優れたものになるはずです。
なぜ上記の分析を行うのでしょうか?
- オープンソース テクノロジーを選択するとき、主な決定要因の 1 つはユーザー数です。ユーザーが少なすぎると、その製品が未熟であることを示します。つまり、何か問題が発生した場合に助けを求める場所がありません。
- 私のテクノロジー選択にはいくつかの原則があります。公式が望ましい(Apache 公式は利用できず、DockerHub 公式のみ)、ユーザー数が多い(1 億人以上)、メンテナンスと更新が頻繁に行われる(7 日前)。
- DockerHubが作成したZookeeperイメージに加えて、Bitnamiが作成したイメージも良い選択です。大衆の目は肥えており、使いやすくなければ、それほど多くの人に推奨してダウンロードすることは不可能です。
- AI Assistantが提供する例では、公式の DockerHub イメージが使用されています。
上で多くのことを述べてきましたが、2 番目の軸の主要な検索エンジンについては言及されていないようです。AIアシスタントによって得られた結果では、シングルノード モードは問題ないようですが、クラスターはmode は常に何かが足りないように感じますが、重要な点はmyidです。私はそれを見ていませんでした。そこで、 Zookeeper をデプロイするために StatefulSetというキーワードを使用して検索エンジンで検索しました。
検索結果には、より参考価値のある 2 つの方向があります。
- K8s 公式文書に記載されている Zookeeper 展開スキームに基づいています。
K8s 公式 Web サイトの分散システム コーディネーターである ZooKeeper を実行するチュートリアル ケースこの例は複雑に見え、いくつかの新しいテクノロジが導入されています。
- Bitnami によって作成されたイメージに基づく Zookeeper クラスターの展開スキーム
得られた情報を整理し、リーダーから指示されたタスクを迅速に完了するために、本日の実証実験計画の順序は次のとおりです。
- AI Assistantによって提供される単一ノード展開構成
- AI Assistantによって提供されるクラスター モード展開構成
- Bitnamiが提供するクラスター モード導入ソリューション
- K8s公式サイト Zookeeper導入事例
なぜなら、単一ノードの展開は比較的簡単だからです。したがって、テストの重要な点は、AI アシスタントとBitnamiが提供するクラスター モードの展開構成が実現可能かどうかです。解決策が実現可能であれば、公式 Web サイトのケースはありません。そうでない場合は、K8s 公式 Web サイトを試してください。 Zookeeper導入事例ですが、正直、当分やりたくないんですが、今回の件は聞いたことのない技術的なポイントがあり、本気でやろうとすると、新たな問題。
Zookeeper の単一ノードの展開
AI アシスタントから返された単一ノードのデプロイメント プランと構成ファイルは問題ないようです。ただし、直接コピーして貼り付けるのではなく、すぐに使用してください。DockerHub 公式 Web サイトのZookeeper 関連の例を必ず参照してください。この 2 つを組み合わせることで、より信頼性の高いリソース リストが生成されます。
考え
K8s クラスター上の単一ノード Zookeeper に必要なリソースのリストは次のとおりです。
PersistentVolumeClaim
ConfigMap:zoo.cfg
導入
クラスターサービス
外部サービス(オプション)
完了する必要があるタスクの目標がわかったら、AI アシスタントによって指定された構成と公式の構成パラメーターに基づいて、一連のリソース構成リストが生成されます。
注: AI アシスタントは大まかなアイデアしか提供しないことが実践で証明されており、詳細にはまだ多くの欠陥があります。次の例のすべてのリソース構成リストは、公式の構成パラメーターと実際の使用要件を参照して編集されています。
何が変わったのか簡単に教えてください。
- Zookeeper のバージョン選択。AI アシスタントによって指定された構成スキームで、公式最新の安定バージョン 3.9.0 の背後にあるバージョン 3.8.2 を使用して3.7.0を置き換えます。
- dataLog構成を追加しました
- リソース制限設定の改善
- zoo.cfgの設定を改善
リソース構成リスト
特に指定しない限り、K8 に関連するすべての操作は Master-0 ノードで実行され、構成ファイルのルート ディレクトリは /srv/opsman/k8s-yaml です。
- インベントリフォルダを作成する
cd /srv/opsman/k8s-yaml
mkdir -p zookeeper/single
cd zookeeper/single
- vi動物園キーパー-pvc.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: zookeeper-data
spec:
accessModes:
- ReadWriteOnce
storageClassName: glusterfs
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: zookeeper-datalog
spec:
accessModes:
- ReadWriteOnce
storageClassName: glusterfs
resources:
requests:
storage: 2Gi
説明:バックエンド ストレージ クラスによって使用されるGlusterFS。
- vi動物園の番人-cm.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: zookeeper-config
data:
zoo-cfg: |
tickTime=2000
dataDir=/data
dataLogDir=/datalog
clientPort=2181
initLimit=10
syncLimit=5
- vizookeeper -deploy.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: zookeeper
spec:
replicas: 1
selector:
matchLabels:
app: zookeeper
template:
metadata:
labels:
app: zookeeper
spec:
containers:
- name: zookeeper
image: zookeeper:3.8.2
resources:
requests:
cpu: 50m
memory: 500Mi
limits:
cpu: '2'
memory: 4000Mi
ports:
- name: zookeeper-2181
containerPort: 2181
protocol: TCP
volumeMounts:
- name: config
mountPath: /conf
- name: data
mountPath: /data
- name: datalog
mountPath: /datalog
volumes:
- name: data
persistentVolumeClaim:
claimName: zookeeper-data
- name: datalog
persistentVolumeClaim:
claimName: zookeeper-datalog
- name: config
configMap:
name: zookeeper-config
items:
- key: zoo-cfg
path: zoo.cfg
---
apiVersion: v1
kind: Service
metadata:
name: zookeeper
spec:
ports:
- name: zookeeper-2181
protocol: TCP
port: 2181
targetPort: 2181
selector:
app: zookeeper
type: ClusterIP
デプロイメントとクラスター サービスは構成ファイルに配置されます。
- vi動物園キーパー-外部-svc.yaml
---
apiVersion: v1
kind: Service
metadata:
name: zookeeper-external-svc
labels:
app: zookeeper-external-svc
spec:
ports:
- name: tcp-zookeeper-external
protocol: TCP
port: 2181
targetPort: 2181
nodePort: 32181
selector:
app: zookeeper
type: NodePort
注: オプションの構成項目。K8s クラスターの外部のサービスからアクセスする必要がない場合、構成は必要ありません。
リソースをデプロイする
- PersistentVolumeClaim のデプロイ
kubectl apply -f zookeeper-pvc.yaml
- ConfigMap のデプロイ
kubectl apply -f zookeeper-cm.yaml
- 導入
kubectl apply -f zookeeper-deploy.yaml
- 外部サービスの導入
kubectl apply -f zookeeper-svc.yaml
K8s導入リソースの検証
- PersistentVolumeClaim の検証
[root@ks-master-0 single]# kubectl get pvc -o wide
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE
zookeeper-data Bound pvc-371c9406-1757-451a-9c89-bed47ac71dd4 1Gi RWO glusterfs 12s Filesystem
zookeeper-datalog Bound pvc-457a134c-0db2-4efc-902c-555daba2057e 2Gi RWO glusterfs 11s Filesystem
- デプロイメントの検証
[root@ks-master-0 single]# kubectl get deploy -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
zookeeper 1/1 1 1 5m1s zookeeper zookeeper:3.8.2 app=zookeeper
- ポッドの検証
[root@ks-master-0 single]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
zookeeper-bcfc6cc5c-bh56m 1/1 Running 0 54s 10.233.120.8 ks-worker-1 <none> <none>
- サービスの検証
[root@ks-master-0 single]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
zookeeper ClusterIP 10.233.58.30 <none> 2181/TCP 59s app=zookeeper
zookeeper-external-svc NodePort 10.233.40.37 <none> 2181:32181/TCP 59s app=zookeeper
Zookeeper サービスの可用性の確認
K8s クラスター内で検証します。
- 検証のために K8s に Zookeeper クライアント ポッドを作成する
kubectl run zookeeper-client --image=zookeeper:3.8.2
- Zookeeper サーバーの接続を確認する
# 进入 Zookeeper Client 容器内部
kubectl exec -it zookeeper-client -- bash
# 连接 Zookeeper Server
bin/zkCli.sh -server 10.233.58.30:2181
# 成功结果如下
[root@ks-master-0 single]# kubectl exec -it zookeeper-client -- bash
root@zookeeper-client:/apache-zookeeper-3.8.2-bin# bin/zkCli.sh -server 10.233.58.30:2181
Connecting to 10.233.58.30:2181
2023-08-07 07:44:16,110 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:zookeeper.version=3.8.2-139d619b58292d7734b4fc83a0f44be4e7b0c986, built on 2023-07-05 19:24 UTC
2023-08-07 07:44:16,117 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:host.name=zookeeper-client
2023-08-07 07:44:16,117 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:java.version=11.0.20
2023-08-07 07:44:16,117 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:java.vendor=Eclipse Adoptium
2023-08-07 07:44:16,117 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:java.home=/opt/java/openjdk
2023-08-07 07:44:16,117 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:java.class.path=/apache-zookeeper-3.8.2-bin/bin/......(此处有省略)
2023-08-07 07:44:16,118 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:java.library.path=/usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib
2023-08-07 07:44:16,118 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:java.io.tmpdir=/tmp
2023-08-07 07:44:16,118 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:java.compiler=<NA>
2023-08-07 07:44:16,118 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:os.name=Linux
2023-08-07 07:44:16,118 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:os.arch=amd64
2023-08-07 07:44:16,118 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:os.version=5.10.0-153.12.0.92.oe2203sp2.x86_64
2023-08-07 07:44:16,118 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:user.name=root
2023-08-07 07:44:16,119 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:user.home=/root
2023-08-07 07:44:16,119 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:user.dir=/apache-zookeeper-3.8.2-bin
2023-08-07 07:44:16,119 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:os.memory.free=42MB
2023-08-07 07:44:16,119 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:os.memory.max=256MB
2023-08-07 07:44:16,120 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:os.memory.total=48MB
2023-08-07 07:44:16,123 [myid:] - INFO [main:o.a.z.ZooKeeper@637] - Initiating client connection, connectString=10.233.58.30:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@18bf3d14
2023-08-07 07:44:16,128 [myid:] - INFO [main:o.a.z.c.X509Util@78] - Setting -D jdk.tls.rejectClientInitiatedRenegotiation=true to disable client-initiated TLS renegotiation
2023-08-07 07:44:16,134 [myid:] - INFO [main:o.a.z.ClientCnxnSocket@239] - jute.maxbuffer value is 1048575 Bytes
2023-08-07 07:44:16,143 [myid:] - INFO [main:o.a.z.ClientCnxn@1741] - zookeeper.request.timeout value is 0. feature enabled=false
Welcome to ZooKeeper!
2023-08-07 07:44:16,171 [myid:10.233.58.30:2181] - INFO [main-SendThread(10.233.58.30:2181):o.a.z.ClientCnxn$SendThread@1177] - Opening socket connection to server zookeeper.default.svc.cluster.local/10.233.58.30:2181.
2023-08-07 07:44:16,173 [myid:10.233.58.30:2181] - INFO [main-SendThread(10.233.58.30:2181):o.a.z.ClientCnxn$SendThread@1179] - SASL config status: Will not attempt to authenticate using SASL (unknown error)
2023-08-07 07:44:16,185 [myid:10.233.58.30:2181] - INFO [main-SendThread(10.233.58.30:2181):o.a.z.ClientCnxn$SendThread@1011] - Socket connection established, initiating session, client: /10.233.118.8:55022, server: zookeeper.default.svc.cluster.local/10.233.58.30:2181
JLine support is enabled
2023-08-07 07:44:16,251 [myid:10.233.58.30:2181] - INFO [main-SendThread(10.233.58.30:2181):o.a.z.ClientCnxn$SendThread@1452] - Session establishment complete on server zookeeper.default.svc.cluster.local/10.233.58.30:2181, session id = 0x1000178f5af0000, negotiated timeout = 30000
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
[zk: 10.233.58.30:2181(CONNECTED) 0]
- サービスの可用性を検証するためのテスト データを作成する
# 创建测试数据
[zk: 10.233.58.30:2181(CONNECTED) 0] create /test test-data1
Created /test
# 读取测试数据
[zk: 10.233.58.30:2181(CONNECTED) 1] get /test
test-data1
K8s クラスターの外側で検証します。
この記事では、K8s Master-0 ノードを直接使用して、テスト検証のために Zookeeper クライアントをインストールします。
- openjdk のインストールはテスト検証に限定されます。
yum install java-11-openjdk
- Zookeeper クライアントをインストールし、Zookeeper 公式 Web サイトにアクセスして、ソフトウェア パッケージの対応するバージョンを見つけます。この記事では、テスト バージョンとして3.8.2を選択します。
# 下载并解压 Zookeeper(在国内源下载)
wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.8.2/apache-zookeeper-3.8.2-bin.tar.gz
tar xvf apache-zookeeper-3.8.2-bin.tar.gz
- Zookeeper サーバーの接続を確認する
cd apache-zookeeper-3.8.2-bin/bin/
./zkCli.sh -server 192.168.9.91:32181
# 成功结果如下(结果有省略)
[root@ks-master-0 bin]# ./zkCli.sh -server 192.168.9.91:32181
/usr/bin/java
Connecting to 192.168.9.91:32181
2023-08-07 15:46:53,156 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:zookeeper.version=3.8.2-139d619b58292d7734b4fc83a0f44be4e7b0c986, built on 2023-07-05 19:24 UTC
......
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
[zk: 192.168.9.91:32181(CONNECTED) 0]
- サービスの可用性を検証するためのテスト データを作成する
# 创建测试数据
[zk: 192.168.9.91:32181(CONNECTED) 0] create /test2 test2-data1
Created /test2
# 读取测试数据
[zk: 192.168.9.91:32181(CONNECTED) 1] get /test2
test2-data1
これまでのところ、Boss によって割り当てられたタスクの半分が完了し、シングルノード Zookeeper の展開が実現し、K8s クラスターの内部と外部で接続性と可用性のテストが実行されました。
しかし、時間は過ぎて二日目となり、未知の任務のため、それはボスが想像していたほど簡単ではありません。
ただし、単一ノードのタスクが完了したため、まず上司にレポートを提出し、実装のアイデア、プロセス、展開プロセス中に発生した問題と解決策を説明します (これが難しいことを上司に直接伝えないように注意してください)。推定時間に問題がある場合は、純粋に検索になります)。
上記のルーチンに従って報告を行った後、上司の理解と承認を得たので(上司は実際に話すのがとても上手です。理由を説明して納得させることができれば)、まずシングルノードの Zookeeper 環境を引き渡します。テストを行ってから、クラスター モードの導入スキームの検討を続けます。
この一連の作戦は批判を受けなかっただけでなく、自分自身の時間を稼ぐことにもなり、完璧でした。!!
クラスター モード Zookeeper の展開
単一ノードに Zookeeper をデプロイするタスクが完了したら、次のステップはクラスター モードでの Zookeeper のデプロイを検討することです。AIアシスタントが提供するデフォルトの例はまったく信頼できず、私は怠け者です。彼を訓練するために。
なぜそんなことを言うのですか?
DockerHub が提供する Zookeeper を使用する AI アシスタントから提供されたソリューションを使用して、K8s クラスターに Zookeeper クラスターをデプロイしようとしたため、2日かかりました (主に病気になって行き詰まり、やり遂げたかったけど、能力が足りなかった!)
次に、私がどのような試みをしたのか、どのような問題に遭遇したのか、そして拷問と狂気の 2 日間 (そのため、ほとんど 3 番目の斧に頼らざるを得ませんでした) の間に私がどのような経験をしたかについて簡単に話したいと思います。
- クラスターモードの鍵は、myid とサーバーの構成を解決することです
- サーバーの構成には問題はありません。構成ファイルに直接記述することも、ENV によって挿入することもできます。
- myid が重要なポイントです。DockHub ミラー ウェアハウスで提供される Zookeeper イメージの場合、ノード myid を動的に構成することはできません。
- 実験では、initContainers、SidecarContainer、 ConfigMap 実装起動スクリプトなどを試しましたが、どれも動作しませんでした。
- DockHub イメージがまったく使用できないわけではありません。起動スクリプトを変更する必要があり、さらにイメージを再起動する必要があるだけです。
- 上記の試みと最終的な製品リソース構成リストの準備はすべて、コマンド ライン インターフェイスよりもはるかに便利な KubeSphere グラフィカル管理コンソールでテストおよび検証されています。
- 経験:成功への道は何千万もあり、1 つが失敗しても、道を変えようとすることができ、最後まで死ぬ必要はありません。私たちの目的は問題を解決することであり、問題を解決できる方法は良い方法であり、行き止まりを掘り下げる精神も状況に応じて異なります
結局のところ、別の方法を見つけるしかありませんが、幸いなことに、これまでの研究で、考えられる解決策が他に 2 つ見つかりました。
- Bitnami によって作成されたイメージを使用して、 Zookeeper クラスター (最終選択) をデプロイします。
- 公式の Kubernetes ドキュメントの例で紹介されているスキームでは、ミラーregistry.k8s.io/kubernetes-zookeeper:1.0-3.4.10を使用し、 PodDisruptionBudgetを使用してサービスの可用性を確保します。
最終選考の理由をお話します。
- ポッド中断予算、少し複雑で、私の現在のランクには適していません。
Pod Disruption Budget (Pod Disruption Budget) は PDB と呼ばれ、Kubernetes バージョン1.21 以上のみがPod Disruption Budget を使用できます。PDB の役割は、マルチレプリカ アプリケーションでの自発的な干渉により同時にダウンする可能性があるポッドの数を制限することです。
この記事では具体的な知識については詳しく説明しませんが、とにかく今は使うつもりはありません(ああ!主に私が理解していないので、混乱するのは避けられません)。公式ドキュメントのPDB導入およびPDB構成事例を参照できます。
- Bitnami によって作成されたイメージは、Zookeeper クラスターをデプロイします。このソリューションについてはインターネット上に多くのリファレンス ケースがあり、このソリューションでは追加の K8S メカニズムを使用せずに Zookeeper のネイティブ デプロイ ソリューションを使用するため、複雑さが軽減されます。これも選択のポイントです。
次に、 Bitnami によって作成されたZookeeperイメージを使用して、 Zookeeperクラスターの展開を完了しようと試み始めました。
考え
K8s クラスター上の一連の Zookeeper クラスターに必要なリソースのリストは次のとおりです。
ステートフルセット
ヘッドレスサービス
ConfigMap:zoo.cfg (使用されません。すべての構成は ENV 形式を使用します)
ConfigMap: setup.sh (起動スクリプト、使用する予定でしたが実際には使用せず、最終的に ENV と Command を採用)
外部サービス(オプション)
注: この記事の構成スキームはセキュリティ構成を考慮していないため、開発環境とテスト環境にのみ適用されます。この記事の例を運用環境で直接使用しないでください。運用環境で使用する前に、公式の構成ドキュメントを参照して、対応する ENV 構成を追加する必要があります。
リソース構成リスト
特に指定しない限り、K8 に関連するすべての操作は Master-0 ノードで実行され、構成ファイルのルート ディレクトリは /srv/opsman/k8s-yaml です。
- インベントリフォルダを作成する
cd /srv/opsman/k8s-yaml
mkdir -p zookeeper/cluster
cd zookeeper/cluster
- vi 動物園キーパー-svc.yaml
---
# Headless Service,用于 Zookeeper 集群之间相互通讯
apiVersion: v1
kind: Service
metadata:
name: zk-hs
labels:
app: zookeeper
spec:
ports:
- name: tcp-client
protocol: TCP
port: 2181
targetPort: 2181
- name: tcp-follower
port: 2888
targetPort: 2888
- name: tcp-election
port: 3888
targetPort: 3888
selector:
app: zookeeper
clusterIP: None
type: ClusterIP
---
# Client Service,用于 K8S 集群内的应用访问 Zookeeper
apiVersion: v1
kind: Service
metadata:
name: zk-cs
labels:
app: zookeeper
spec:
ports:
- name: tcp-client
protocol: TCP
port: 2181
targetPort: 2181
selector:
app: zookeeper
type: ClusterIP
- vi 動物園キーパー-sts.yaml
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: zookeeper
labels:
app: zookeeper
spec:
replicas: 3
selector:
matchLabels:
app: zookeeper
serviceName: zk-hs
template:
metadata:
name: zookeeper
labels:
app: zookeeper
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: "app"
operator: In
values:
- zookeeper
topologyKey: "kubernetes.io/hostname"
containers:
- name: zookeeper
image: bitnami/zookeeper:3.8.2
command:
- bash
- '-ec'
- |
HOSTNAME="$(hostname -s)"
if [[ $HOSTNAME =~ (.*)-([0-9]+)$ ]]; then
ORD=${BASH_REMATCH[2]}
export ZOO_SERVER_ID="$((ORD + 1 ))"
else
echo "Failed to get index from hostname $HOST"
exit 1
fi
exec /entrypoint.sh /run.sh
resources:
limits:
cpu: 1
memory: 2Gi
requests:
cpu: 50m
memory: 500Mi
env:
- name: ZOO_ENABLE_AUTH
value: "no"
- name: ALLOW_ANONYMOUS_LOGIN
value: "yes"
- name: ZOO_SERVERS
value: >
zookeeper-0.zk-hs.default.svc.cluster.local:2888:3888
zookeeper-1.zk-hs.default.svc.cluster.local:2888:3888
zookeeper-2.zk-hs.ddefault.svc.cluster.local:2888:3888
ports:
- name: client
containerPort: 2181
- name: follower
containerPort: 2888
- name: election
containerPort: 3888
livenessProbe:
tcpSocket:
port: client
failureThreshold: 6
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
readinessProbe:
tcpSocket:
port: client
failureThreshold: 6
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
volumeMounts:
- name: data
mountPath: /bitnami/zookeeper
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "glusterfs"
resources:
requests:
storage: 2Gi
例証します:
- 私は最も基本的なENV構成のみを使用しました。焦点はZOO_SERVERSです。パラメーターの使用方法の詳細については、Bitnami 公式ドキュメントを参照してください。
- 起動コマンドはCommandに直接記述することも、ConfigMap にしてスクリプトとしてマウントすることもできます。
- default.svc.cluster.local 、FQDN はこの方法でのみ記述できることに注意してください。クラスター ドメイン名がopsman.topであっても、FQDN をカスタムとして記述しないでください(これは従来の問題であり、手遅れです)注意深く読んでください。それについては後で話しましょう)
- vi 動物園キーパー-外部-svc.yaml
---
# External Client Service,用于 K8S 集群外部访问 Zookeeper
apiVersion: v1
kind: Service
metadata:
name: zookeeper-external-svc
labels:
app: zookeeper-external-svc
spec:
ports:
- name: tcp-zookeeper-external
protocol: TCP
port: 2181
targetPort: 2181
nodePort: 32181
selector:
app: zookeeper
type: NodePort
注: オプションの構成項目。K8s クラスターの外部のサービスからアクセスする必要がない場合、構成は必要ありません。
リソースをデプロイする
- クラスターとヘッドレスサービスのデプロイ
kubectl apply -f zookeeper-svc.yaml
- StatefulSet のデプロイ
kubectl apply -f zookeeper-sts.yaml
- 外部サービスを導入する
kubectl apply -f zookeeper-external-svc.yaml
K8s導入リソースの検証
- PersistentVolumeClaim の検証
[root@ks-master-0 cluster]# kubectl get pvc -o wide
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE
data-zookeeper-0 Bound pvc-342c3869-17ca-40c7-9db0-755d5af0f85f 2Gi RWO glusterfs 2m7s Filesystem
data-zookeeper-1 Bound pvc-6744813f-0f5b-4138-8ffc-387f63044af3 2Gi RWO glusterfs 47s Filesystem
data-zookeeper-2 Bound pvc-731edc8d-189a-4601-aa64-a8d6754d93ec 2Gi RWO glusterfs 28s Filesystem
- ステートフルセットの検証
[root@ks-master-0 cluster]# kubectl get sts -o wide
NAME READY AGE CONTAINERS IMAGES
zookeeper 3/3 2m3s zookeeper bitnami/zookeeper:3.8.2
- ポッドの検証
[root@ks-master-0 cluster]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
zookeeper-0 1/1 Running 0 2m42s 10.233.118.45 ks-worker-2 <none> <none>
zookeeper-1 1/1 Running 0 83s 10.233.120.17 ks-worker-1 <none> <none>
zookeeper-2 1/1 Running 0 64s 10.233.115.99 ks-worker-0 <none> <none>
- サービスの検証
[root@ks-master-0 cluster]# kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
zk-cs ClusterIP 10.233.43.229 <none> 2181/TCP 3m58s app=zookeeper
zk-hs ClusterIP None <none> 2181/TCP,2888/TCP,3888/TCP 3m58s app=zookeeper
zookeeper-external-svc NodePort 10.233.45.5 <none> 2181:32181/TCP 10s app=zookeeper
Zookeeper クラスターのステータスの確認
- StatefulSet によって作成された Pod 構成のホスト名を確認する
[root@ks-master-0 cluster]# for i in 0 1 2; do kubectl exec zookeeper-$i -- hostname; done
zookeeper-0
zookeeper-1
zookeeper-2
- StatefulSet によって作成された Pod 構成の完全修飾ドメイン名 (Fully Qualified Domain Name、FQDN) を確認します。
[root@ks-master-0 cluster]# for i in 0 1 2; do kubectl exec zookeeper-$i -- hostname -f; done
zookeeper-0.zk-hs.default.svc.cluster.local
zookeeper-1.zk-hs.default.svc.cluster.local
zookeeper-2.zk-hs.default.svc.cluster.local
- 各 Zookeeper サービスの myid ファイルの内容を確認します。
[root@ks-master-0 cluster]# for i in 0 1 2; do echo "myid zookeeper-$i";kubectl exec zookeeper-$i -- cat /bitnami/zookeeper/data/myid; done
myid zookeeper-0
1
myid zookeeper-1
2
myid zookeeper-2
3
- Zookeeper によって生成された構成ファイルを確認する
[root@ks-master-0 cluster]# kubectl exec -it zookeeper-0 -- cat /opt/bitnami/zookeeper/conf/zoo.cfg | grep -vE "^#|^$"
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/bitnami/zookeeper/data
clientPort=2181
maxClientCnxns=60
autopurge.snapRetainCount=3
autopurge.purgeInterval=0
preAllocSize=65536
snapCount=100000
maxCnxns=0
reconfigEnabled=false
quorumListenOnAllIPs=false
4lw.commands.whitelist=srvr, mntr
maxSessionTimeout=40000
admin.serverPort=8080
admin.enableServer=true
server.1=zookeeper-0.zk-hs.default.svc.cluster.local:2888:3888;2181
server.2=zookeeper-1.zk-hs.default.svc.cluster.local:2888:3888;2181
server.3=zookeeper-2.zk-hs.default.svc.cluster.local:2888:3888;2181
- クラスターのステータスを確認する
[root@ks-master-0 cluster]# for i in 0 1 2; do echo -e "# myid zookeeper-$i \n";kubectl exec zookeeper-$i -- /opt/bitnami/zookeeper/bin/zkServer.sh status;echo -e "\n"; done
# myid zookeeper-0
/opt/bitnami/java/bin/java
ZooKeeper JMX enabled by default
Using config: /opt/bitnami/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: leader
# myid zookeeper-1
/opt/bitnami/java/bin/java
ZooKeeper JMX enabled by default
Using config: /opt/bitnami/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: follower
# myid zookeeper-2
/opt/bitnami/java/bin/java
ZooKeeper JMX enabled by default
Using config: /opt/bitnami/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Mode: follower
Zookeeper サービスの可用性の確認
K8s クラスター内で検証します。
- K8s で Zookeeper クライアント ポッド検証を作成します (単一ノードの検証中に作成されるため、再度作成する必要はありません)
kubectl run zookeeper-client --image=zookeeper:3.8.2
- Zookeeper サーバーの接続を確認する
# 进入 Zookeeper Client 容器内部
kubectl exec -it zookeeper-client -- bash
# 连接 Zookeeper Server( 10.233.43.229 是 Cluster Service 的 IP)
bin/zkCli.sh -server 10.233.43.229:2181
# 成功结果如下(内容有省略)
[root@ks-master-0 cluster]# kubectl exec -it zookeeper-client -- bash
root@zookeeper-client:/apache-zookeeper-3.8.2-bin# bin/zkCli.sh -server 10.233.43.229:2181
Connecting to 10.233.43.229:2181
2023-08-08 10:08:40,864 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:zookeeper.version=3.8.2-139d619b58292d7734b4fc83a0f44be4e7b0c986, built on 2023-07-05 19:24 UTC
.....
2023-08-08 10:08:40,872 [myid:] - INFO [main:o.a.z.ZooKeeper@637] - Initiating client connection, connectString=10.233.43.229:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@18bf3d14
2023-08-08 10:08:40,886 [myid:] - INFO [main:o.a.z.c.X509Util@78] - Setting -D jdk.tls.rejectClientInitiatedRenegotiation=true to disable client-initiated TLS renegotiation
2023-08-08 10:08:40,892 [myid:] - INFO [main:o.a.z.ClientCnxnSocket@239] - jute.maxbuffer value is 1048575 Bytes
2023-08-08 10:08:40,903 [myid:] - INFO [main:o.a.z.ClientCnxn@1741] - zookeeper.request.timeout value is 0. feature enabled=false
Welcome to ZooKeeper!
2023-08-08 10:08:40,920 [myid:10.233.43.229:2181] - INFO [main-SendThread(10.233.43.229:2181):o.a.z.ClientCnxn$SendThread@1177] - Opening socket connection to server zk-cs.default.svc.cluster.local/10.233.43.229:2181.
2023-08-08 10:08:40,923 [myid:10.233.43.229:2181] - INFO [main-SendThread(10.233.43.229:2181):o.a.z.ClientCnxn$SendThread@1179] - SASL config status: Will not attempt to authenticate using SASL (unknown error)
JLine support is enabled
2023-08-08 10:08:40,948 [myid:10.233.43.229:2181] - INFO [main-SendThread(10.233.43.229:2181):o.a.z.ClientCnxn$SendThread@1011] - Socket connection established, initiating session, client: /10.233.118.8:38050, server: zk-cs.default.svc.cluster.local/10.233.43.229:2181
2023-08-08 10:08:41,064 [myid:10.233.43.229:2181] - INFO [main-SendThread(10.233.43.229:2181):o.a.z.ClientCnxn$SendThread@1452] - Session establishment complete on server zk-cs.default.svc.cluster.local/10.233.43.229:2181, session id = 0x10007253d840000, negotiated timeout = 30000
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
[zk: 10.233.43.229:2181(CONNECTED) 0]
- サービスの可用性を検証するためのテスト データを作成する
# 创建测试数据
[zk: 10.233.43.229:2181(CONNECTED) 0] create /test test-data1
Created /test
# 读取测试数据
[zk: 10.233.43.229:2181(CONNECTED) 1] get /test
test-data1
K8s クラスターの外側で検証します。
- Zookeeper サーバーの接続を確認する
# 进入 Zookeeper 安装包的 bin 目录
cd apache-zookeeper-3.8.2-bin/bin/
# 连接 Zookeeper Server( 192.168.9.91 是 K8S Master-0 节点的 IP,32181 是 External Service 定义的 NodePort 端口号)
./zkCli.sh -server 192.168.9.91:32181
# 成功结果如下(结果有省略)
[root@ks-master-0 bin]# ./zkCli.sh -server 192.168.9.91:32181
/usr/bin/java
Connecting to 192.168.9.91:32181
2023-08-08 18:13:52,650 [myid:] - INFO [main:o.a.z.Environment@98] - Client environment:zookeeper.version=3.8.2-139d619b58292d7734b4fc83a0f44be4e7b0c986, built on 2023-07-05 19:24 UTC
......
2023-08-08 18:13:52,660 [myid:] - INFO [main:o.a.z.ZooKeeper@637] - Initiating client connection, connectString=192.168.9.91:32181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@5c072e3f
2023-08-08 18:13:52,666 [myid:] - INFO [main:o.a.z.c.X509Util@78] - Setting -D jdk.tls.rejectClientInitiatedRenegotiation=true to disable client-initiated TLS renegotiation
2023-08-08 18:13:52,671 [myid:] - INFO [main:o.a.z.ClientCnxnSocket@239] - jute.maxbuffer value is 1048575 Bytes
2023-08-08 18:13:52,686 [myid:] - INFO [main:o.a.z.ClientCnxn@1741] - zookeeper.request.timeout value is 0. feature enabled=false
Welcome to ZooKeeper!
2023-08-08 18:13:52,708 [myid:192.168.9.91:32181] - INFO [main-SendThread(192.168.9.91:32181):o.a.z.ClientCnxn$SendThread@1177] - Opening socket connection to server ks-master-0/192.168.9.91:32181.
2023-08-08 18:13:52,709 [myid:192.168.9.91:32181] - INFO [main-SendThread(192.168.9.91:32181):o.a.z.ClientCnxn$SendThread@1179] - SASL config status: Will not attempt to authenticate using SASL (unknown error)
JLine support is enabled
2023-08-08 18:13:52,721 [myid:192.168.9.91:32181] - INFO [main-SendThread(192.168.9.91:32181):o.a.z.ClientCnxn$SendThread@1011] - Socket connection established, initiating session, client: /192.168.9.91:45004, server: ks-master-0/192.168.9.91:32181
2023-08-08 18:13:52,776 [myid:192.168.9.91:32181] - INFO [main-SendThread(192.168.9.91:32181):o.a.z.ClientCnxn$SendThread@1452] - Session establishment complete on server ks-master-0/192.168.9.91:32181, session id = 0x10007253d840001, negotiated timeout = 30000
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
[zk: 192.168.9.91:32181(CONNECTED) 0]
- サービスの可用性を検証するためのテスト データを作成する
# 创建测试数据
[zk: 192.168.9.91:32181(CONNECTED) 0] create /test2 test2-data1
Created /test2
# 读取测试数据(读取了 2次 测试数据)
[zk: 192.168.9.91:32181(CONNECTED) 1] get /test
test-data1
[zk: 192.168.9.91:32181(CONNECTED) 2] get /test2
test2-data1
これまでのところ、Zookeeper クラスター モードの展開が実装されており、K8S クラスターの内部と外部で接続性と可用性のテストが実行されています。
KubeSphere管理コンソールで確認する
スクリーンショットをいくつか撮って、KubeSphere 管理コンソールに表示される Zookeeper 関連のリソースの効果を確認します。
- ステートフルセット
- ポッド
- サービス
要約する
この記事では、KubeSphere ベースの K8s クラスター上で Zookeeper のシングル ノードおよびクラスター モードをインストール、デプロイ、テスト、検証するプロセスを詳しく紹介します。関係する詳細は次のように要約されます。
- AI アシスタントと検索エンジンを使用して O&M タスクの完了を支援する方法。
- DockerHub によって提供される公式 Zookeeper イメージを使用して、K8s クラスターに単一ノード Zookeeper サービスをデプロイし、テストを検証する方法。
- Bitnami が提供する Zookeeper イメージを使用して、K8s クラスターに Zookeeper クラスター サービスをデプロイし、テストを検証する方法。
- PodDisruptionBudget を使用して Zookeeper クラスターをデプロイする例が紹介されていますが、実際には検証されていません。
この記事の構成スキームは、開発およびテスト環境で直接使用できますが、運用環境でも一定の参照の意味があります。
この記事は、ブログ用のマルチポスト プラットフォームであるOpenWriteによって公開されています。