tech.guitarrapc.cóm

Technical updates

ローカルのRedis ClusterにVisual Studioでデバッグ実行する

以前の記事で、Docker Composeを使ってローカルマシンにRedis Clusterを構築しました。 今回は少し発展させて、Visual Studioで同Docker Composeにアプリケーションをコンテナ起動 & デバッグ実行する方法を紹介します。

接続図

ちょっと何を言っているかよくわからないってなりそうなので、まずはどのような接続をしたいのかを説明します。

Docker Composeを使ってRedis ClusterとVisual Studioのアプリケーションをコンテナ起動します。Visual StudioのDocker Compose統合でコンテナ実行したアプリケーションをデバッグ実行できるという寸法です。 Docker Composeのファイル的には次のようなイメージです。

services:
  # Visual Studoでデバッグ実行するアプリケーション
  redisfailover.direct:
    image: ${DOCKER_REGISTRY-}redisfailoverdirect
    build:
      context: src/Redis/RedisFailover.Direct
      dockerfile: Dockerfile

  # Redis Cluster
  redis-node-0:
    image: docker.io/bitnami/redis-cluster:7.2
    environment:
      - 'REDIS_PASSWORD=bitnami'
      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'

  redis-node-1:
    image: docker.io/bitnami/redis-cluster:7.2
    environment:
      - 'REDIS_PASSWORD=bitnami'
      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'

  redis-node-2:
    image: docker.io/bitnami/redis-cluster:7.2
    environment:
      - 'REDIS_PASSWORD=bitnami'
      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'

  redis-node-3:
    image: docker.io/bitnami/redis-cluster:7.2
    environment:
      - 'REDIS_PASSWORD=bitnami'
      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'

  redis-node-4:
    image: docker.io/bitnami/redis-cluster:7.2
    environment:
      - 'REDIS_PASSWORD=bitnami'
      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'

  redis-node-5:
    image: docker.io/bitnami/redis-cluster:7.2
    depends_on:
      - redis-node-0
      - redis-node-1
      - redis-node-2
      - redis-node-3
      - redis-node-4
    environment:
      - 'REDIS_PASSWORD=bitnami'
      - 'REDISCLI_AUTH=bitnami'
      - 'REDIS_CLUSTER_REPLICAS=1'
      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'
      - 'REDIS_CLUSTER_CREATOR=yes'
    ports:
      - 6379:6379

図にすると次のような構成です。

flowchart LR
  subgraph "ホストマシン"
    visualstudio["Visual Studio"]
  end
  subgraph "Docker Desktop"
    subgraph "Docker Compose"
      redisfailover.direct
      subgraph "Redis Cluster"
        redis-node-0
        redis-node-1
        redis-node-2
        redis-node-3
        redis-node-4
        redis-node-5
      end
    end
  end
  redisfailover.direct --クラスターエンドポイント---> redis-node-5
  redisfailover.direct -. 必要に応じてスロット先ノードに切り替え .-> redis-node-4
  redisfailover.direct -. 必要に応じてスロット先ノードに切り替え .-> redis-node-3
  redisfailover.direct -. 必要に応じてスロット先ノードに切り替え .-> redis-node-2
  redisfailover.direct -. 必要に応じてスロット先ノードに切り替え .-> redis-node-1
  redisfailover.direct -. 必要に応じてスロット先ノードに切り替え .-> redis-node-0
  visualstudio --vsdbg--> redisfailover.direct

image

ポイントは「ホストからRedis Clusterの各ノードにはホスト名で直接接続できない」制約です。Docker Compose内で解決される各ホスト名を使ってRedis Clusterの各ノードをつないでいるため、スロット先の接続先がこのホスト名(redis-node-0とか)になります。このホスト名はCompose内では解決できますがホストマシンからは解決できないので、ホストマシンからRedis Clusterの接続しスロットが別ノードの場合、ホストからそのノードへの接続名1が解決できず接続エラーになります。

そこで、Visual StudioのDocker Compose統合を使ってアプリケーションを同Docker Composeでコンテナ起動します。アプリケーションはRedis Clusterのホスト名が解決できるの、でRedis Clusterのスロットが別ノードに格納されていても問題なく接続できます。開発者は、Visual Studioから同コンテナ上のアプリケーションにデバッガーをさした状態なので、いつも通りVSデバッグできます。2

ホストから繋げないことは別に問題ではなく、Visual Studioでデバッグできればいいという考え方です。

Visual StudioのDocker Compose統合

Visual Studioにはコンテナオーケストレーションサポートがあります。csprojを右クリック > Add > Container Orchestrator Support... でDocker Composeを追加できます。

image

image

追加するとslnと同じパスに以下のファイルができます。

  • docker-compose.dcproj
  • docker-compose.override.yml
  • docker-compose.yml
  • .dockerignore

見慣れないdocker-compose.dcprojはVisual StudioのDocker Compose統合の象徴で、このファイルがVisual Studioで認識されると、Visual StudioにDocker Composeプロファイルができて、指定したcsprojのアプリケーションをコンテナビルド & Docker Composeで実行します。

image

docker-compose.yamlには右クリックしたcsprojのコンテナ定義が書かれており、docker-compose.override.ymlにはデバッグ実行用のオーバーライド設定が書かれています。ASP.NET Coreの環境名やエンドポイントが環境変数で上書き指定されています。

# docker-compose.yaml
services:
  redisfailover.direct:
    image: ${DOCKER_REGISTRY-}redisfailoverdirect
    build:
      context: src/Redis/RedisFailover.Direct
      dockerfile: Dockerfile

# docker-compose.override.yml
services:
  redisfailover.direct:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_HTTP_PORTS=8080
    ports:
      - "8080"

このdocker-compose.yamlに起動したいコンテナを追加すれば、アプリケーションから名前解決できる状態を作れそうですね?次節でRedis Clusterを追加してみましょう。

Redis ClusterをDocker Composeに追加

Visual StudioのDocker Compose統合で追加されたdocker-compose.ymlにRedis Clusterを追加します。Visual StudioのDocker Composeプロファイルでデバッグ実行すると、Redis Clusterとアプリケーションが同じDocker Composeで起動します。

services:
  redisfailover.direct:
    image: ${DOCKER_REGISTRY-}redisfailoverdirect
    build:
      context: src/Redis/RedisFailover.Direct
      dockerfile: Dockerfile

  redis-node-0:
    image: docker.io/bitnami/redis-cluster:7.2
    environment:
      - 'REDIS_PASSWORD=bitnami'
      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'

  redis-node-1:
    image: docker.io/bitnami/redis-cluster:7.2
    environment:
      - 'REDIS_PASSWORD=bitnami'
      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'

  redis-node-2:
    image: docker.io/bitnami/redis-cluster:7.2
    environment:
      - 'REDIS_PASSWORD=bitnami'
      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'

  redis-node-3:
    image: docker.io/bitnami/redis-cluster:7.2
    environment:
      - 'REDIS_PASSWORD=bitnami'
      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'

  redis-node-4:
    image: docker.io/bitnami/redis-cluster:7.2
    environment:
      - 'REDIS_PASSWORD=bitnami'
      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'

  redis-node-5:
    image: docker.io/bitnami/redis-cluster:7.2
    depends_on:
      - redis-node-0
      - redis-node-1
      - redis-node-2
      - redis-node-3
      - redis-node-4
    environment:
      - 'REDIS_PASSWORD=bitnami'
      - 'REDISCLI_AUTH=bitnami'
      - 'REDIS_CLUSTER_REPLICAS=1'
      - 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'
      - 'REDIS_CLUSTER_CREATOR=yes'
    ports:
      - 6379:6379

コンテナ起動したアプリケーションがRedis Clusterに接続できるように、appsettings.jsonにDocker Composeで起動したRedis Clusterへの接続情報を書いておきましょう。

{
  "ConnectionStrings": {
    "Redis1": "redis-node-5:6379,ssl=false,keepAlive=60,password=bitnami",
    "Redis2": "redis-node-5:6379,ssl=false,keepAlive=60,password=bitnami"
  }
}

用意完了です。

デバッグ実行

Docker Composeプロファイルでデバッグ実行しましょう。

image

Visual StudioのContainers Windowを見ると、dockercomposeXxxxxとしてRedis Clusterの各ノードとアプリケーションコンテナがまとめて起動しているのがわかります。

image

Containers WindowのLogsをみると、Redis Clusterの各ノードが起動しているのがわかります。

image

このアプリケーションはSwagger統合しているASP.NET Coreアプリケーションなので、デバッグ実行するとコンテナのSwagger UIがブラウザで開きます。

image

RedisへのSetStringを実行すると無事に実行できたことがログからわかります。Redis Cluster接続も確認できます。

image

RedisFailover.Direct | info: RedisFailover.Direct.Infrastructures.ElastiCacheConnectionContext[0]
RedisFailover.Direct |       Connecting to redis: ElastiCache/Unspecified/redis-node-5:6379

このアプリケーションは、以前の記事で紹介したフェイルオーバー処理が入っています。アプリケーションが接続していたredis-node-05を終了させてみましょう。ログから接続切断イベントを拾って別ノードとつながって自動復旧しているのがわかります。

image

ちなみに複数ノードをストップさせることで、CLUSTER DOWNを再現したり、そこからノードを起動してコネクションが自動復旧することも確認できます。

ローカルRedis Clusterを組んでもフェイルオーバー処理の確認は難しい

今回みはRedis Clusterの中に6シャード(0-5)を起動していますがレプリカは存在しません。このため、ElastiCacheやMemoryDBに期待するようなレプリカのフェイルオーバー処理は確認できません。

このため、フェイルオーバー処理を確認するなら、基本的な接続切断回りまではこの仕組みで動作確認しつつ、フェイルオーバー挙動自体はElastiCacheやMemoryDBを用いて確認したほうがいいでしょう。

まとめ

Redis ClusterとVisual Studioを連携させて、アプリケーションのデバッグ実行をできることを示しました。コンテナを使うメリットはホストマシンにアプリケーションを構築せず、こういった検証が簡単にできることです。また、Visual StudioのDocker Compose統合はコンテナのデバッグ実行を簡単にできるので、ぜひ使ってみてください。

Redis Clusterの仕組みは軽くしか触れていないので、Redis Clusterの仕組みを理解したい方はRedis cluster specification | Docs | Redisを参照してください。Redis Clusterを知るいいチャンスです。


  1. クライアントに通知されるスロット先のノード接続先は、Redis Clusterにノード参加時のホスト名になるため。
  2. ブレークポイント、F10やF11のステップ実行やウォッチ式も問題なく実行できます。