この記事は、Huawei Cloud Community「Istioに基づいたマルチクラスタートラフィック管理の実装」から著者によって共有されています。友達を作ることができます。
背景
マルチクラウドやハイブリッド クラウドなどの異種インフラストラクチャのサービス ガバナンスは、Istio がサポートに重点を置いているシナリオの 1 つです。サービスの可用性を向上させ、ベンダーロックインを回避するために、企業は通常、複数のリージョンの複数のクラスターにアプリケーションをデプロイすることを選択するか、マルチクラウドやハイブリッドクラウドなどの複数のクラウド環境にアプリケーションをデプロイすることを選択します。マルチクラスターソリューションが徐々に最適なものになってきています。エンタープライズ アプリケーションの展開の選択肢。このため、クラスタ間のサービス ガバナンスに対する強い要求を持つユーザーが増えており、Istio は ServiceMesh 分野の事実上の標準として、さまざまなマルチクラスタ管理ソリューションを発表しています。
2. はじめに
現在、Istio は 4 つのマルチクラスター モデルをサポートしています。
- フラット ネットワークの単一コントロール プレーン モデル
- フラットネットワークマルチコントロールプレーンモデル
- 非フラット ネットワークの単一コントロール プレーン モデル
- 非フラットネットワークマルチコントロールプレーンモデル
マルチクラスターの単一コントロール プレーン モデルは、複数のクラスターが同じ Istio コントロール プレーンを共有することを意味します。マルチクラスターのマルチコントロール プレーン モデルは、単一コントロールであるかどうかに関係なく、各クラスターが Istio コントロール プレーンのセットを独立して使用する必要があることを意味します。プレーンまたはマルチ コントロール プレーン モデルの場合、Istio コントロール プレーン (istiod) の各セットはすべてのクラスターの Kube-apiserver に接続する必要があり、List-Watch はすべてのクラスターを取得しService、Endpoint、Pod 、Node
、クラスター内またはクラスター間のサービス アクセスを制御します。メイン クラスターの Istio API オブジェクトのみを監視しますVirtualService、DestinationRule、Gateway
。
クラスター間ネットワークがフラットであるかどうかに応じて、Istio は 2 つのコントロール プレーン モデルに細分化されます。
- フラット ネットワーク: マルチクラスターのコンテナー ネットワークは VPN およびその他のテクノロジーを通じて接続されており、ポッドはクラスター間で直接アクセスできます。
- 非フラット ネットワーク: 各クラスターのコンテナー ネットワークは相互に分離されており、クラスター間アクセスはパススルーできず、East-West ゲートウェイを経由する必要があります。
実稼働環境で Istio マルチクラスター モデルを選択する場合は、実際のシナリオに基づいて決定を下す必要があります。クラスター間のネットワークがフラットな場合はフラット ネットワーク モデルを選択でき、クラスター間のネットワークが分離されている場合は非フラット ネットワーク モデルを選択できます。クラスターのサイズが小さい場合は、単一のコントロール プレーン モデルを選択できます。クラスターのサイズが大きい場合は、複数のコントロール プレーン モデルを選択できます。
このドキュメントでは、インストール手順のために非フラット ネットワーク マルチ コントロール プレーン モデルを選択します。 インストール モデルは次のとおりです。 ノン
フラット ネットワーク マルチ コントロール プレーン モデルには次の特徴があります。
- 異なるクラスターが 1 つの大きなネットワークの下にある必要はありません。つまり、コンテナー ネットワークが 3 つのレイヤーで接続されている必要はなく、クラスター間のサービス アクセスは
Istio East-West Gateway
転送を通じて行われます。 - 各 Kubernetes クラスターのポッド アドレス範囲とサービス アドレス範囲に制限はなく、他のクラスターと重複することができ、異なるクラスターが相互に干渉することはありません。
- 各 Kubernetes クラスターのサイドカーは、このクラスターの Istio コントロール プレーンにのみ接続されるため、通信がより効率的になります。
- Istiod はメイン クラスターの Istio 構成のみを監視するため、他のリソースの冗長レプリケーションの問題が発生します。
VirtualService、DestinationRule、Gateway
- 同じクラスター内の内部サービス アクセス: ポッド間の直接接続。クラスター間サービス アクセス: DNS プロキシに依存して他のクラスターのサービス ドメイン名を解決します。クラスター間のネットワークは相互に分離されているため、クラスター間の転送トラフィックに依存します。リモートクラスター。
East-west Gateway
3つのClusterMesh環境構築
2 つのクラスター (cluster1 とクラスター 2) を構築し、各クラスターに Istio コントロール プレーンをインストールし、両方をプライマリ クラスターとして設定します。クラスタークラスター 1 はネットワーク 1 ネットワーク上にあり、クラスタークラスター 2 はネットワーク 2 ネットワーク上にあります。
3.1 前提条件
このビルドの環境情報は次のとおりです。Kind を使用して Kubernetes クラスターを構築します。Kind のバージョンは v0.19.0 です。 Kubernetes のバージョンは 1.27.3、Istio のバージョンは 1.20.1 です。
k8s クラスターを構築する前に、docker kubectl と kind が Linux ノードにインストールされていることを確認してください。
istioctlバイナリをダウンロードする
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.20.1 TARGET_ARCH=x86_64 sh -
istioctl クライアントをパスに追加します

3.2 Kubernetes クラスターのインストール
クラスタ 1 およびクラスタ 2 のインストール スクリプトは次のとおりです。
# クラスターの作成.sh # このスクリプトは、kind と # 安全でないコンテナー レジストリを作成および構成する機能。 set -o xtrace set -o が発生しました set -o 名詞セット set -o パイプ失敗 # シェルチェックソース=util.sh NUM_CLUSTERS="${NUM_CLUSTERS:-2}" KIND_IMAGE="${KIND_IMAGE:-}" KIND_TAG="${KIND_TAG:-v1.27.3@sha256:3966ac761ae0136263ffdb6cfd4db23ef8a83cba8a463690e98317add2c9ba72}" OS="$(名前)" 関数 create-clusters() { ローカルの num_clusters=${1} ローカル画像引数="" if [[ "${KIND_IMAGE}" ]];それから image_arg="--image=${KIND_IMAGE}" elif [[ "${KIND_TAG}" ]];それから image_arg="--image=kindest/node:${KIND_TAG}" なれ for i in $(seq "${num_clusters}");する kind create クラスター --name "cluster${i}" "${image_arg}" 修正クラスター「${i}」 エコー 終わり } 関数 fixup-cluster() { ローカル i=${1} # クラスター番号 if [ "$OS" != "ダーウィン" ];then # クラスターが他のクラスターの kube API サーバーに到達できるように、コンテナーの IP アドレスを kube API エンドポイントとして設定します。 ローカルの docker_ip docker_ip=$(docker Inspection --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "cluster${i}-control-plane") kubectl config set-cluster "kind-cluster${i}" --server="https://${docker_ip}:6443" なれ # コンテキスト名を簡略化します kubectl config rename-context "kind-cluster${i}" "cluster${i}" } echo "${NUM_CLUSTERS} 個のクラスターを作成しています" クラスターの作成 "${NUM_CLUSTERS}" kubectl config use-context クラスター1 echo "種類の CIDR は $(docker network Inspection -f '{{$map :=index .IPAM.Config 0}}{{index $map "Subnet"}}' kind)" エコー「完了」
apiserver
上記のクラスターのインストール プロセス中に、istiod が他のクラスターのアドレスにアクセスできるように、kube-apiserver
クラスター アドレスはマスター ノードのアドレスに設定されます。これは種類別にデプロイされたクラスターであるため、2 つのクラスターのマスター ノードは基本的に同じホスト上で docker を実行するコンテナーです。
クラスター1とクラスター2の準備ができているかどうかを確認します

3.3 MetalLB を使用して外部 IP をゲートウェイに割り当てる
kind は複数のクラスターのデプロイに使用されるため、istio North-South ゲートウェイと East-West ゲートウェイの作成には LoadBalancer サービスの作成が必要であり、どちらも ExternalIP の使用を必要とします。ここでは、LB IP アドレスの配布とアナウンスを実現するために metalLB が使用されます。
ノード サブネット セグメントを使用してクラスターを構築するには、「種類」を参照してください: metalLB L2 モードで展開します。 172.18.0.0/16
クラスタ 1 の metalLB 構成リスト: metallb-config-1.yaml
### クラスター 1 の場合 ##lbip アドレスを割り当てるために IPAddressPool を構成します。 L2 モードでは、ippool アドレスとワーカー ノードを同じサブネット内に置くことができます。 APIバージョン: metallb.io/v1beta1 種類: IPアドレスプール metadata: 名前: 最初のプール 名前空間: metallb-system 仕様: 住所: - 172.18.1.230-172.18.1.240 --- ##アドレスアナウンス用のL2アドバタイズメントを設定する APIバージョン: metallb.io/v1beta1 種類: L2広告 metadata: 名前: 初級者 名前空間: metallb-system 仕様: ipアドレスプール: - 最初のプール
cluster2 クラスターの metalLB 構成リスト: metallb-config-2.yaml
### クラスター 2 の場合 ##lbip アドレスを割り当てるために IPAddressPool を構成します。 L2 モードでは、ippool アドレスとワーカー ノードを同じサブネット内に置くことができます。 APIバージョン: metallb.io/v1beta1 種類: IPアドレスプール metadata: 名前: 第 2 プール 名前空間: metallb-system 仕様: 住所: - 172.18.1.241-172.18.1.252 --- ##アドレスアナウンス用のL2アドバタイズメントを設定する APIバージョン: metallb.io/v1beta1 種類: L2広告 metadata: 名前: 2 番目の上級 名前空間: metallb-system 仕様: ipアドレスプール: - 2番目のプール
スクリプトを使用してインストールする
#!/usr/bin/env bash set -o xtrace set -o が発生しました set -o 名詞セット set -o パイプ失敗 NUM_CLUSTERS="${NUM_CLUSTERS:-2}" for i in $(seq "${NUM_CLUSTERS}");する echo "クラスター${i} での metallb デプロイメントを開始しています" kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.10/config/manifests/metallb-native.yaml --context "cluster${i}" kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)" --context "cluster${i}" ## 待機時間を増やします。metallb ロードがデプロイされていない場合、IPAddressPool L2 アドバタイズメントの作成時にエラーが報告されます。 睡眠10 kubectl apply -f ./metallb-config-${i}.yaml --context "cluster${i}" エコー " - - " 終わり
metalLB の展開ステータスを確認する
IPAddressPool 情報を確認します。

3.4 クラスター共有ルート CA 構成の信頼関係
安全なクラスタ間 mTLS 通信をサポートするために、マルチ コントロール プレーン モデルでは、各クラスタのコントロール プレーン Istiod が、Citatel と同じ CA 機関によって発行された中間 CA 証明書を使用して、クラスタ間 TLS 双方向認証をサポートする証明書を発行する必要があります。 。
Istio east-west ゲートウェイ (クロスクラスター アクセス) は、動作時に SNI ベースのルーティングを使用し、TLS によって要求された SNI に基づいて、SNI に対応するクラスターに自動的にルーティングします。すべてのトラフィックを TLS で暗号化する必要があります。
証明書とキーをクラスターに挿入します。スクリプトは次のとおりです (スクリプトは istio インストール パッケージ ディレクトリに移動する必要があります)。
#!/usr/bin/env bash set -o xtrace #set -o が発生しました set -o 名詞セット set -o パイプ失敗 NUM_CLUSTERS="${NUM_CLUSTERS:-2}" ##istio インストール パッケージの最上位ディレクトリに証明書とキーを保存するディレクトリを作成します。 mkdir -p 証明書 プッシュ証明書 ##ルート証明書とキーを生成する make -f ../tools/certs/Makefile.selfsigned.mk root-ca for i in $(seq "${NUM_CLUSTERS}");する ##クラスターごとに、Istio CA の中間証明書とキーを生成します。 make -f ../tools/certs/Makefile.selfsigned.mk "cluster${i}-cacerts" ##クラスターごとに、 istio-system 名前空間を作成します kubectl create namespace istio-system --context "cluster${i}" ## クラスターごとに、istio システム名前空間に topology.istio.io/network タグを付けてネットワーク ID を追加します。 kubectl --context="cluster${i}" ラベル名前空間 istio-system topology.istio.io/network="network${i}" ##クラスターごとに、作業ノードにリージョンと可用性ゾーンのラベルを付けて、istio がリージョン フェイルオーバーとリージョン ロード バランシングを実装しやすくします。 kubectl --context="cluster${i}" ラベル ノード "cluster${i}-control-plane" topology.kubernetes.io/region="region${i}" kubectl --context="cluster${i}" ラベル ノード "cluster${i}-control-plane" topology.kubernetes.io/zone="zone${i}" #各クラスターで、すべての入力ファイル ca-cert.pem、ca-key.pem、root-cert.pem、および cert-chain.pem を使用して、プライベート cacerts を作成します。 kubectl delete secret cacerts -n istio-system --context "cluster${i}" kubectl create secret generic cacerts -n istio-system --context "cluster${i}" \ --from-file="cluster${i}/ca-cert.pem" \ --from-file="cluster${i}/ca-key.pem" \ --from-file="cluster${i}/root-cert.pem" \ --from-file="cluster${i}/cert-chain.pem" エコー " - - " 終わり
3.5 Istio サービス メッシュのインストール
クラスター 1 クラスターとクラスター 2 クラスターにマルチ コントロール プレーン istio グリッドをインストールします。
メインクラスターとしてcluster1を設定し、istioのインストールディレクトリで以下のコマンドを実行します。
cat <<EOF > クラスタ1.yaml apiバージョン: install.istio.io/v1alpha1 種類: IstioOperator 仕様: 値: グローバル: メッシュID: メッシュ1 multiCluster: ##マルチクラスター構成を有効にする クラスタ名: クラスタ1 #k8s クラスタ名を指定します network: network1 #ネットワーク識別子を指定します ロギング: レベル: デバッグ 終了後
メインクラスターとしてcluster2を設定し、istioのインストールディレクトリで以下のコマンドを実行します。
cat <<EOF > クラスタ2.yaml apiバージョン: install.istio.io/v1alpha1 種類: IstioOperator 仕様: 値: グローバル: メッシュID: メッシュ2 multiCluster: ##マルチクラスター構成を有効にする ClusterName:cluster2 #k8s クラスター名を指定します network: network2 #ネットワーク識別子を指定します ロギング: レベル: デバッグ 終了後
#!/usr/bin/env bash set -o xtrace set -o が発生しました set -o 名詞セット set -o パイプ失敗 OS="$(名前)" NUM_CLUSTERS="${NUM_CLUSTERS:-2}" for i in $(seq "${NUM_CLUSTERS}");する echo "クラスター${i} で istio デプロイメントを開始しています" istioctl install --force --context="cluster${i}" -f "cluster${i}.yaml" echo "クラスター ${i} に Eastwest ゲートウェイを生成します" ## 各クラスターに East-West ゲートウェイをインストールします。 bash サンプル/multicluster/gen-eastwest-gateway.sh \ --mesh "mesh${i}" --cluster "cluster${i}" --network "network${i}" | \ istioctl --context="cluster${i}" install -y -f - エコー 終わり
スクリプトを実行して istio をインストールおよびデプロイします
インストールが完了するまでしばらく待ちます
3.6 East-West ゲートウェイでサービスを開始する
クラスターは異なるネットワーク上にあるため、両方のクラスターの East-West ゲートウェイですべてのサービス (*.local) を開く必要があります。このゲートウェイはインターネット上でパブリックですが、その背後にあるサービスには、同じネットワーク上にあるかのように、信頼された mTLS 証明書を持つサービスのみがアクセスできます。次のコマンドを実行して、両方のクラスターのサービスを公開します。
apiバージョン: networking.istio.io/v1beta1 種類: ゲートウェイ metadata: 名前: クロスネットワークゲートウェイ 仕様: セレクタ: istio: eastwestgateway # East-West トラフィック用の専用ゲートウェイ サーバー: - ポート: 番号: 15443 # すでに宣言されています 名前:TLS プロトコル: TLS TL: mode: AUTO_PASSTHROUGH # East-West ゲートウェイの動作モードは TLS AUTO_PASSTHROUGH です ホスト: - "*.local" # すべてのサービスを公開する
上記のゲートウェイ構成を各クラスターに個別に適用します。
kubectl -n istio-system --context=cluster${i} apply -f samples/multicluster/expose-services.yaml
3.7 istiod がリモート クラスター apiserver にアクセスできるようにシークレットを構成する
各 k8s クラスターの istiod は、他のクラスターの Kube-APIServer を List-Watch し、K8s クラスターの認証情報を使用して Secret オブジェクトを作成し、Istio がリモート Kubernetes API サーバーにアクセスできるようにする必要があります。
#!/usr/bin/env bash set -o xtrace set -o が発生しました set -o 名詞セット set -o パイプ失敗 OS="$(名前)" NUM_CLUSTERS="${NUM_CLUSTERS:-2}" for i in $(seq "${NUM_CLUSTERS}");する $(seq "${NUM_CLUSTERS}") の j の場合;する if [ "$i" -ne "$j" ] それから echo "クラスター${i} とクラスター${j} の間のエンドポイント検出を有効にする" if [ "$OS" == "ダーウィン" ] それから # クラスターが他のクラスターの kube API サーバーに到達できるように、コンテナーの IP アドレスを kube API エンドポイントとして設定します。 docker_ip=$(docker Inspection -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "cluster${i}-control-plane") istioctl 作成-リモート-シークレット \ --context="cluster${i}" \ --server="https://${docker_ip}:6443" \ --name="クラスター${i}" | \ kubectl apply --validate=false --context="cluster${j}" -f - それ以外 istioctl 作成-リモート-シークレット \ --context="cluster${i}" \ --name="クラスター${i}" | \ kubectl apply --validate=false --context="cluster${j}" -f - なれ なれ 終わり 終わり
上記のスクリプトを実行すると、リモート シークレットが作成されます。
istiod ログを確認すると、リモート クラスターがすでに監視されていることがわかります。
Istio マルチクラスター トラフィック管理の 4 つの実践方法
kubectl create --context=cluster1 名前空間のサンプル kubectl create --context=cluster2 名前空間のサンプル kubectl label --context=cluster1 名前空間サンプル \ istio-injection=有効 kubectl label --context=cluster2 名前空間サンプル \ istio-injection=有効 kubectl apply --context=cluster1 \ -f サンプル/helloworld/helloworld.yaml \ -l サービス=helloworld -n サンプル kubectl apply --context=cluster2 \ -f サンプル/helloworld/helloworld.yaml \ -l サービス=helloworld -n サンプル
異なるクラスターに異なるバージョンのサービスをデプロイする
アプリケーション helloworld-v1 をクラスタ 1 にデプロイします。kubectl apply --context=cluster1 \ -f サンプル/helloworld/helloworld.yaml \ -l バージョン=v1 -n サンプルアプリケーション helloworld-v2 をクラスター 2 にデプロイします。
kubectl apply --context=cluster2 \ -f サンプル/helloworld/helloworld.yaml \ -l バージョン=v2 -n サンプルテストクライアントをデプロイする
kubectl apply --context=cluster1 \ -f サンプル/スリープ/sleep.yaml -n サンプル kubectl apply --context=cluster2 \ -f サンプル/スリープ/sleep.yaml -n サンプル
ロード インスタンスが正常にデプロイされ、サイドカーが挿入されたことを確認します。

4.1 クラスタ間トラフィックの検証
Sleep ポッドを使用してサービス HelloWorld を繰り返し呼び出します。ロード バランシングが期待どおりに機能していることを確認するには、サービス HelloWorld をすべてのクラスターから呼び出す必要があります。
クラスター 1 の Sleep ポッドからサービス HelloWorld にリクエストを送信します。
クラスター 2 の Sleep ポッドからサービス HelloWorld にリクエストを送信します。
4.3 ゲートウェイからのアクセスを確認する
ゲートウェイ経由でサーバー Helloworld にアクセスします
virtualserviceやgatewayなどのistioリソースを作成する構成一覧は以下のとおりです。
# helloworld-gateway.yaml apiバージョン: networking.istio.io/v1beta1 種類: ゲートウェイ metadata: 名前: helloworld ゲートウェイ 仕様: セレクタ: istio: ingressgateway # istio のデフォルト コントローラーを使用する サーバー: - ポート: 数: 80 名前: http プロトコル: HTTP ホスト: -「*」 --- apiバージョン: networking.istio.io/v1beta1 種類: 仮想サービス metadata: 名前: ハローワールド 仕様: ホスト: -「*」 ゲートウェイ: - helloworld-ゲートウェイ http: - マッチ: - タイプ: 正確: /こんにちは ルート: - 行き先: ホスト: ハローワールド ポート: 数: 5000
注: この構成は両方のクラスターに適用する必要があります。
アクセス効果は以下の通りです。

4.3 リージョン負荷分散の検証
トラフィックをさらにきめ細かく制御するには、2 つの領域の重みをそれぞれ 80% と 20% に設定し、DestinationRule を使用して重み配分を構成します。 region1 -> zone1
region1 -> zone2
# 地域-lb-weight.yaml apiバージョン: networking.istio.io/v1beta1 種類: DestinationRule metadata: 名前: ハローワールド 名前空間: サンプル 仕様: ホスト: helloworld.sample.svc.cluster.local トラフィックポリシー: 接続プール: http: 接続ごとの最大リクエスト数: 1 ロードバランサー: シンプル: ROUND_ROBIN 地域Lb設定: 有効: true 配布する: - 送信元: リージョン1/* に: "領域1/*": 80 "領域2/*": 20 - 送信元: リージョン2/* に: "領域2/*": 80 "領域1/*": 20 外れ値検出: 連続5xxエラー: 1 間隔: 1秒 ベース射出時間: 1m
注: この構成は両方のクラスターに適用する必要があります。
ゲートウェイを介してcluster1からサービスHelloWorldにリクエストを送信します。
ゲートウェイを介してcluster2からサービスHelloWorldにリクエストを送信します。

4.4 リージョンフェイルオーバーの検証
複数のサービス インスタンスが複数のリージョン/リージョンにデプロイされている場合、特定のリージョン/リージョンのサービス インスタンスが利用できない場合、トラフィックを他のリージョン/リージョンのサービス インスタンスに転送してリージョン フェイルオーバーを実現し、サービスの信頼性を確保できます。
# locality-lb-failover.yaml apiバージョン: networking.istio.io/v1beta1 種類: DestinationRule metadata: 名前: ハローワールド 名前空間: サンプル 仕様: ホスト: helloworld.sample.svc.cluster.local トラフィックポリシー: 接続プール: http: maxRequestsPerConnection: 1 # HTTP キープアライブをオフにして、各 HTTP リクエストに新しい接続ポリシーを使用するように強制します ロードバランサー: シンプル: ROUND_ROBIN localityLbSetting: # リージョン負荷分散構成。外れ値検出をオンにすると、デフォルトでオンになります。 有効: true フェイルオーバー: # リージョンフェイルオーバー戦略 - 出身地: 地域1 宛先: リージョン2 - 出身地: 地域2 宛先: 地域1 外れ値検出: Continuous5xxErrors:1 #1 連続 5xx エラー 間隔: 1s # 検出間隔 1s 基本射出時間: 1m #基本射出時間 1m
注: この構成は両方のクラスターに適用する必要があります。
ゲートウェイを介してcluster1からサービスHelloWorldにリクエストを送信します。
障害をシミュレートし、cluster1 クラスター内の Helloworld V1 バージョンを失敗するように手動で設定します。
再度アクセスすると、障害検出が有効になり、フェイルオーバーがトリガーされ、応答内のバージョンが常に v2 であることが確認されます。これは、リージョン 2 の helloworld サービスにアクセスしていることを意味し、リージョン フェイルオーバーが実現します。
フェイルオーバーの前提条件は、現在のリージョン内のすべてのインスタンスが使用できない場合、現在のリージョンに転送されることです。それ以外の場合、トラフィックは現在のリージョン内の他の使用可能なインスタンスに送信されます。
5つのコメント
参考文献は以下のとおりです。
-
istio オープン ソース コミュニティ (クロスネットワーク マルチプライマリ アーキテクチャのインストール手順): https://istio.io/latest/zh/docs/setup/install/multicluster/multi-primary_multi-network/
-
kind インストールクラスタースクリプトリファレンス: https://github.com/cnych/multi-cluster-istio-kind/tree/main/kind-create
-
マルチクラスター証明書管理リファレンス: https://istio.io/latest/zh/docs/tasks/security/cert-management/plugin-ca-cert/
JetBrains 2024 (2024.1) の最初のメジャー バージョン アップデートは オープンソースです。Microsoft も費用を支払う予定です。なぜオープンソースが依然として批判されているのでしょうか? [復旧] Tencent Cloud バックエンドがクラッシュ: コンソールにログイン後、大量のサービス エラーとデータなし ドイツも 「独立して制御可能」にする必要がある 州政府は 30,000 台の PC を Windows から Linux deepin-IDE に移行し、最終的に達成ブートストラッピング! Visual Studio Code 1.88 がリリースされました. 良い人です、Tencent は Switch を本当に「思考する学習マシン」に変えました. RustDesk リモート デスクトップが起動し、Web クライアントを再構築します. SQLite に基づく WeChat のオープン ソース ターミナル データベースである WCDB がメジャー アップグレードされました.