サイドカー コンテナーを使用して Azure Container Instances をデプロイする

完了

顧客の現在の API では、アプリケーション API へのトラフィックは暗号化されずに実行されています。 顧客は、アプリケーションで HTTP ではなく HTTPS を使用することを望んでいます。 HTTPS をサポートするようにアプリケーション コードを更新することはできますが、元のアプリケーションにはアクセスできません。

代替策は、アプリケーション コードを変更することなく必要な SSL 機能でアプリケーションを強化する "サイドカー" コンテナーを使用することです。 サイドカー パターンは、コンテナーベース アーキテクチャにおける強力な概念であり、アプリケーションの機能を、同じコンテナー グループ内で一緒に実行されるさまざまなコンテナー イメージに分解できます。

Azure Container Instances コンテナー グループでは、各コンテナーがアプリケーションで必要な機能の一部を引き受けることができます。 サイドカー コンテナーでは、アプリケーション コンテナーから (ことなるイメージ リポジトリからでも) のさまざまなコンテナー イメージを使用できます。 同じコンテナー グループ内のコンテナーは、根底のネットワーク スタックなど、いくつかのプロパティを共有しています。

Note

コンテナー グループの概念は、Kubernetes における "ポッド" に相当します。

このユニットでは、コンテナーの 1 つが Secure Sockets Layer (SSL) の暗号化と解読を行い、もう 1 つのコンテナーがアプリケーション API 機能を提供するコンテナー グループをデプロイします。 Secure Sockets Layer (SSL) 機能をオフロードするために、オープンソースの Web サーバーである NGINX を Web アプリケーションの前のリバース プロキシとして使用します。 暗号化されたトラフィックは NGINX コンテナー内の Azure Container Instances コンテナー グループに入り、NGINX が解読されたトラフィックを実際のアプリケーション コンテナーに渡します。

次の図に、このトポロジを示します。

Diagram that shows topology of Azure Container Instances with NGINX sidecar.

NGINX 構成を作成する

まず、データ暗号化用のデジタル証明書を作成してから、NGINX 構成を含むファイルを作成します。 構成ファイルのすべての詳細を理解する必要はありませんが、以下の点が重要です。

  • proxy_pass プロパティは、アプリケーション コンテナーの場所である http://127.0.0.1:8080 を指します。 コンテナー グループ内の NGINX コンテナーとアプリケーション コンテナーは同じネットワーク名前空間を共有するため、localhost または 127.0.0.1 アドレスを使用することでお互いと通信できます。
  • 証明書ファイルとキーは /etc/nginx/ ディレクトリから読み取られるため、コンテナーをデプロイするときに、生成された証明書ファイルをそのディレクトリに入れる必要があります。
  • サイドカー コンテナーは TCP ポート 443 をリッスンします。
  1. Azure portal の Cloud Shell で、次のコードを実行して、データ暗号化用のデジタル証明書を取得します。 このユニットでは、自己署名証明書を使用しますが、運用時には証明機関 (CA) によって生成された証明書を使用することになります。

    # Create self-signed certs
    openssl req -new -newkey rsa:2048 -nodes -keyout ssl.key -out ssl.csr -subj "/C=US/ST=WA/L=Redmond/O=AppDev/OU=IT/CN=contoso.com"
    openssl x509 -req -days 365 -in ssl.csr -signkey ssl.key -out ssl.crt
    
  2. 次のコードを実行して NGINX 構成ファイルを作成します。

    # Create nginx.conf for SSL
    nginx_config_file=/tmp/nginx.conf
    cat <<EOF > $nginx_config_file
    user nginx;
    worker_processes auto;
    events {
      worker_connections 1024;
    }
    pid        /var/run/nginx.pid;
    http {
        server {
            listen [::]:443 ssl;
            listen 443 ssl;
            server_name localhost;
            ssl_protocols              TLSv1.2;
            ssl_ciphers                ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK;
            ssl_prefer_server_ciphers  on;
            ssl_session_cache    shared:SSL:10m; # a 1mb cache can hold about 4000 sessions, so you can hold 40000 sessions
            ssl_session_timeout  24h;
            keepalive_timeout 75; # up from 75 secs default
            add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains';
            ssl_certificate      /etc/nginx/ssl.crt;
            ssl_certificate_key  /etc/nginx/ssl.key;
            location / {
                proxy_pass http://127.0.0.1:8080 ;
                proxy_set_header Connection "";
                proxy_set_header Host \$host;
                proxy_set_header X-Real-IP \$remote_addr;
                proxy_set_header X-Forwarded-For \$remote_addr;
                proxy_buffer_size          128k;
                proxy_buffers              4 256k;
                proxy_busy_buffers_size    256k;
            }
        }
    }
    EOF
    
  3. 次のコードを実行して、base64 エンコードされた変数に、NGINX サイドカー コンテナーに渡したいファイルを収集します。

    # Encode to Base64
    nginx_conf=$(cat $nginx_config_file | base64)
    ssl_crt=$(cat ssl.crt | base64)
    ssl_key=$(cat ssl.key | base64)
    

NGINX サイドカーを使用してコンテナー グループをデプロイする

サイドカーなどの複雑な構成では、Azure CLI ではなく YAML を使用する必要があります。 YAML を使用してコンテナー グループを定義します。

  1. 変数に格納したすべての情報を組み合わせることで、サイドカー コンテナーのプロパティを指定する YAML ファイルを作成します。 以下の点に注意してください。

    • SQL パスワードは安全な環境変数として渡されるため、コンテナー インスタンスの作成後に公開されることはありません。
    • NGINX コンテナーは、証明書が見つかると想定される /etc/nginx/ ディレクトリに構成ボリュームをマウントします。 ボリューム コンテンツはシークレットとして指定されます。これが先に変数を base64 でエンコードした理由です。
    • NGINX コンテナーではポート 443 が公開され、アプリケーション コンテナーではポート 8080 が公開されます。 しかし、コンテナー グループはポート 443 のみを公開し、NGINX サイドカー コンテナー経由でしかアプリケーションに到達できないようにします。
    # Create YAML
    aci_subnet_id=$(az network vnet subnet show -n $aci_subnet_name --vnet-name $vnet_name -g $rg --query id -o tsv)
    aci_yaml_file=/tmp/aci_ssl.yaml
    cat <<EOF > $aci_yaml_file
    apiVersion: '2023-05-01'
    location: $location
    name: $aci_name
    properties:
      subnetIds:
      - id: $aci_subnet_id
      containers:
      - name: nginx
        properties:
          image: nginx
          ports:
          - port: 443
            protocol: TCP
          resources:
            requests:
              cpu: 1.0
              memoryInGB: 1.5
          volumeMounts:
          - name: nginx-config
            mountPath: /etc/nginx
      - name: sqlapi
        properties:
          image: erjosito/yadaapi:1.0
          environmentVariables:
          - name: SQL_SERVER_USERNAME
            value: $sql_username
          - name: SQL_SERVER_PASSWORD
            secureValue: $sql_password
          - name: SQL_SERVER_FQDN
            value: $sql_server_fqdn
          ports:
          - port: 8080
            protocol: TCP
          resources:
            requests:
              cpu: 1.0
              memoryInGB: 1
      volumes:
      - secret:
          ssl.crt: "$ssl_crt"
          ssl.key: "$ssl_key"
          nginx.conf: "$nginx_conf"
        name: nginx-config
      ipAddress:
        ports:
        - port: 443
          protocol: TCP
        type: Private
      osType: Linux
    tags: null
    type: Microsoft.ContainerInstance/containerGroups
    EOF
    
  2. 必要なすべての構成で YAML ファイルを作成した後、次の Azure CLI コマンドを実行してコンテナー インスタンスを作成します。

    # Deploy ACI
    az container create -g $rg --file $aci_yaml_file
    
  3. 構成をテストするには、コンテナー インスタンスのプライベート IP アドレスを抽出し、テスト VM から HTTPS 経由でこれにアクセスします。 このユニットでは自己署名証明書を使用するので、証明書検証を無効にするために curl でフラグ -k を使用します。 追加された curl フラグ -s は、curl の出力の詳細を減らすために使用されます。

    # Test
    aci_ip=$(az container show -n $aci_name -g $rg --query 'ipAddress.ip' -o tsv) && echo $aci_ip
    ssh -n -o BatchMode=yes -o StrictHostKeyChecking=no $vm_pip "curl -ks https://$aci_ip/api/healthcheck"
    

    API の api/healthcheck エンドポイントは、OK で応答するはずです。