投稿者「yosk222」のアーカイブ

MacでTypeScripのAWS CDKを試す

本記事では、AWSのGetting Started with the AWS CDKのチュートリアルを参考にAWS CDKを使ったTypeScriptを試してみた記録です。

  • AWS CDKのインストール
  • TypeScriptテンプレートのダウンロード
  • TypeScriptの作成
    • ライブラリファイルの作成
    • 実行ファイルの作成
  • TypeScriptのコンパイル
  • デプロイ環境の準備
  • AWSリソースのデプロイ

AWS CDKのインストール

以下のコマンドを利用してaws-cdkをグローバルインストールします。cdkコマンドをプロジェクトごとに管理したい場合は、-gオプションを外してローカルインストールする必要があります。

$ npm install -g aws-cdk
$ cdk --version
2.4.0 (build 993f14d)

TypeScriptテンプレートのダウンロード

利用できるTypeScriptのテンプレートは以下の通りで、app、lib、sample-appが選択できます。今回はappを選択します。

Available templates:
* app: Template for a CDK Application
   └─ cdk init app --language=typescript
* lib: Template for a CDK Construct Library
   └─ cdk init lib --language=typescript
* sample-app: Example CDK Application with some constructs
   └─ cdk init sample-app --language=typescript

プロジェクト用のディレクトリを作成し、appテンプレートをダウンロードします。ダウンロードが完了するとTypeScriptのコンパイルに必要なファイルが作成されます。

$ mkdir aws-cdk
$ cd aws-cdk/
$ cdk init app --language typescript
~~省略~~
✅ All done!

TypeScriptの作成

ライブラリファイルの作成

lib配下には、TypeScriptの雛形ファイルが作成されます。チュートリアルのS3サンプルコードを利用して以下のように編集します。これは、aws-cdk-test-bucketという名前のS3バケットを作成するだけのコードです。なお、クラス名であるTestS3StackはCloudFormationのスタック名になります。

import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { aws_s3 as s3 } from 'aws-cdk-lib';

export class TestS3Stack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);
    const bucket = new s3.Bucket(this, 'CdkTestBucket', {
        bucketName: 'aws-cdk-test-bucket',
        versioned: true,
        websiteRedirect: {hostName: 'aws.amazon.com'}});
  }
}

実行ファイルの作成

bin配下には、lib配下で作成したクラスのインスタンを生成して実行するためのTypeScriptコードがあります。以下のように編集してTestS3Stackを実行するように設定します。

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { TestS3Stack } from '../lib/aws-cdk-stack';

const app = new cdk.App();
new TestS3Stack(app, 'TestS3Stack', {});

TypeScriptのコンパイル

編集したTypeScriptをビルドします。ビルドが完了するとJavaScriptファイルが生成されます。

$ npm run build

> aws-cdk@0.1.0 build
> tsc

$ cdk ls
TestS3Stack

作成したTypeScriptをCloudFormationの形式に変換したい場合は以下のコマンドを利用します。

$ cdk synth
Resources:
  CdkTestBucket3821C40C:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: aws-cdk-test-bucket
      VersioningConfiguration:
        Status: Enabled
      WebsiteConfiguration:
        RedirectAllRequestsTo:
          HostName: aws.amazon.com
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain
    Metadata:
      aws:cdk:path: TestS3Stack/CdkTestBucket/Resource
~~省略~~

デプロイ環境の準備

bootstrapコマンドを使用して、cdkを利用してデプロイできる環境を構築します。ここでは、CDKToolkitという名前のCloudFormationスタックが実行されます。

# aws cliの設定をしていない場合はあらかじめ設定しておきます。
$ aws configure
$ cdk bootstrap
~~省略~~
 ✅  Environment aws://[AWSのアカウントID]/[CLIで設定しているリージョン] bootstrapped.

実行が完了するとS3のバケットが作成されます。間違ってこのS3バケットを削除してしまうと、デプロイ時にエラーが発生します。その際は、CloudFormationのStackを削除して再度cdk bootstrapを実行してください。

$ aws s3 ls
2022-01-09 14:38:26 [バケット名]

#上記のバケットを削除してcdk deployを実行すると以下のエラーが発生します。
[100%] fail: No bucket named ‘バケット名’. Is account ‘アカウント名’ bootstrapped?

AWSリソースのデプロイ

deployコマンドを使用してTypeScriptに記述したバケットを作成します。一度CloudFormationの形式に変換された後、TestS3Stackという名前のスタックが作成されて実行されます。

$ cdk deploy

✨  Synthesis time: 8.98s

TestS3Stack: deploying...
[0%] start: Publishing ~~省略~~
[100%] success: Published ~~省略~~
TestS3Stack: creating CloudFormation changeset...

 ✅  TestS3Stack

✨  Deployment time: 50.63s

Stack ARN:
~~省略~~

✨  Total time: 59.6s

AWS上で確認すると、以下の通りバケットが作成されていました。

$ aws s3 ls | grep aws-cdk-test-bucket
2022-01-09 15:58:02 aws-cdk-test-bucket

以上です。

MacでTypeScriptをインストールしてコンパイルを試す

  • TypeScriptとは
  • Node.jsのインストール
  • TypeScriptのインストール
  • TypeScriptでコンパイルを試す

TypeScriptとは

TypeScriptを一言で説明すると、独自の構文からJavaScriptにコンパイルするためのツールです。JavaScriptとの大きな違いは型定義が必要な点です。

https://www.typescriptlang.org

JavaScriptは型を定義しないで開発できますが、開発する上で多くの弊害があります。例えば、ソースコードを読む時に何の変数かが一目で分かりませんし、その変数に間違った型を定義するとプログラムが実行されるまで気付くことができません。

TypeScriptでは独自の構文からJavaScriptを生成することで、それらの欠点を補います。JavaScriptの可読性を向上したり、定義を強制したり、型エラーを実行前に検知したりすることで開発生産性を向上します。TypeScriptはJavaScriptのコードを綺麗に保つ上で今後重宝されていくと思います。

Node.jsのインストール

以下のコマンドでNode.jsの推奨バージョンをインストールします。推奨バージョンは、こちらから確認できます。

$ brew install nodebrew
# nodebrew installで"Failed to create the file"のエラーが出た場合は以下のコマンドを実行
$ mkdir -p .nodebrew/src
# 推奨バージョンのインストール
$ nodebrew install-binary v16.13.1
Fetching: https://nodejs.org/dist/v16.13.1/node-v16.13.1-darwin-x64.tar.gz
########################################################################################################################## 100.0%
Installed successfully

インストールが完了したら、以下のコマンドでパスを通します。毎回パスを通すのが面倒な方は~/.bash_profileに登録しておくと便利です。

$ nodebrew use v16.13.1
use v16.13.1
$ export PATH=$HOME/.nodebrew/current/bin:$PATH
$ node -v
v16.13.1

TypeScriptのインストール

TypeScriptをプロジェクトで管理するため、ディレクトリを作成して以下のコマンドでローカルインストールを実行します。

$ mkdir getting-start
$ cd getting-start/
$ npm install --save-dev typescript tslint @types/node

TypeScriptでコンパイルを試す

TypeScriptでコンパイルし、型定義のエラーを出力するところまで実施します。

String型で定義した変数に文字列を代入するだけのindex.tsを作成します。なお、TypeScriptの拡張子はtsです。

let message: string
message = "Hello World"

以下のコマンドでコンパイルします。コンパイルするときには、コンパイルオプションを指定する”tsconfig.json”が必要です。今回は何も指定せずにコンパイルするので、中身を空にしています。

$ touch tsconfig.json
$ ./node_modules/.bin/tsc

index.tsファイルと同じディレクトリにindex.jsファイルが生成されています。中身を確認すると、JavaScriptに変換されていることがわかります。

$ cat index.js
var message;
message = "Hello World";

JavaScriptではmessage変数の型が定義されていませんので、messageに数値を代入してもJavaScriptでは問題ありません。しかしTypeScriptでは型を定義しており、数値を代入することができません。この挙動を確認してみます。

index.tsファイルを以下のように編集します。

let message: string
message = 1

再度コンパイルすると、messageに異なる型を代入しているのでエラーが出力されます。

$ ./node_modules/.bin/tsc
index.ts:2:1 - error TS2322: Type 'number' is not assignable to type 'string'.

2 message = 1
  ~~~~~~~

Found 1 error.

本記事では以上とします。

xcrun: error: active developer path (“***”) does not existが出たときの解決策

rbenv installコマンドを利用してRubyのインストールをしていたら、以下のエラーが発生しました。

xcrun: error: active developer path ("/Applications/Xcode.app/Contents/Developer") does not exist
Use `sudo xcode-select --switch path/to/Xcode.app` to specify the Xcode that you wish to use for command line developer tools, or use `xcode-select --install` to install the standalone command line developer tools.
See `man xcode-select` for more details.

xcode-selectコマンドが参照するパスが存在しないというエラーです。どうやらXcode Appをアンインストールしたことによって、もともと参照していたパスが無くなったことで発生していました。

しかし、コマンドラインツールはインストール済みでしたので、再度Xcode Appを再インストールせずにコマンドラインツールのパスを切り替えることにしました。

$ xcode-select --install
xcode-select: error: command line tools are already installed, use "Software Update" to install updates

以下のコマンドでコマンドラインツールの参照先を変更し、エラーが解消されました。

$ xcode-select -print-path
/Applications/Xcode.app/Contents/Developer
$ sudo xcode-select --switch /Library/Developer/CommandLineTools/
$ xcode-select -print-path
/Library/Developer/CommandLineTools

以上です。

Macでディレクトリ配下のファイルの先頭行に一括で文字列を挿入する

あまり利用することもないと思いますが、備忘録として記載します。

作成したファイルの冒頭に特定の文字列を一律で追加したい時は、以下のコマンドを覚えておくと便利です。例えば、開発したソースコードの冒頭に、コピーライトなどのコメントを後から追加することになった場合などに有用です。

$ ls -l -d $(find 対象ディレクトリ名 -type f) | awk '{print $9}' | xargs -Ix sed -i -e '1s/^/挿入したい文字列\'$'\n/' x

以上です。

PythonのPyGithubでコンテンツをPushする

PyGithubを使って、PythonプログラムからGitHubに対してコンテンツをPushする方法について解説します。

  • 環境情報
  • PyGithubをインストールする
  • PyGithubを使ってコンテンツをPushする
    • create_fileメソッドを利用する
    • create_git_commitメソッドを利用する

環境情報


本記事は、以下の環境を基に解説します。

  • OS・・・MacOS Catalina 10.15.5
  • Python・・・Python 3.9.1
  • PyGithub・・・1.54.1

PyGithubをインストールする


pipコマンドを利用して、PyGithubをインストールします。

$ pip install PyGithub

PyGithubを使ってコンテンツをPushする


PyGithubでGithubにPushする方法として、以下二つがあります。本節では、これらの方法について紹介します。

  • create_fileメソッドを利用する
  • create_git_commitメソッドを利用する

create_fileメソッドを利用する


create_fileメソッドを利用すると、コンテンツをGitHubにPushするところまで実施します。

PyGithubのRepositoryクラスのメソッドで、引数は以下の通りです。branch、comitter、authorは必須ではなく、レポジトリのファイルパス(path)、Commit時のメッセージ(message)、ファイルの内容(content)が必須の引数です。

create_file(path, message, content, branch=NotSet, committer=NotSet, author=NotSet)

プログラムとして利用する場合は、以下のようにGithub.get_repoメソッドを利用してRepositoryクラスを定義する必要があります。

github_source = Github( base_url="https://github.com/api/v3", login_or_token=[GithubのToken] )
repo = github_source.get_repo( [GithubのOrganization/GitHubのRepository] )
repo.create_file( [ファイルパス],  [Commitのメッセージ], [ファイルの内容] )

しかし、create_fileメソッドは一つのファイルをPushします。従って、複数のファイルをPushする場合はファイルごとにPushするので、処理時間が長くなります。複数のファイルをまとめてPushしたい場合は、create_git_commitを利用します。

create_git_commitメソッドを利用する


create_git_commitを利用して、複数のファイルを一括でCommitしてPushする方法について解説します。

PyGithubのRepositoryクラスのメソッドで、引数は以下の通りです。author、comitterは必須ではなく、Commit時のメッセージ(message)、新たにアタッチするGitTree(tree)、GitTreeを追加したいCommit情報(parents)が必須の引数です。

create_git_commit(message, tree, parents, author=NotSet, committer=NotSet)

GitTreeとは、ファイルのコンテンツ(GitTreeElement)のリストです。つまり、既に存在するCommit情報がparents、新たにListに登録するファイルのコンテンツがtreeに該当します。

プログラムとして利用する場合は、以下の流れで記述します。

  1. InputGitTreeElementメソッドで登録したファイルコンテンツをlist(elements)に登録します(6~7行目)。ここでPushしたいファイルを複数まとめて登録できます。
  2. 既存のGitTree(base_tree)を取得し、ファイルコンテンツのlist(elements)をマージしたGitTree(new_tree)を作成します(9~12行目)。
  3. 最新のCommit情報(latest_commit)を取得します(13行目)。
  4. ファイルコンテンツをPushします(14~15行目)。
github_source = Github( base_url="https://github.com/api/v3", login_or_token=[GithubのToken] )
repo = github_source.get_repo( repo_path )
elements = list()

#ここでPushしたいファイルをfor文などを利用して複数登録する。
element = InputGitTreeElement( [ファイルパス], '100644', 'blob', [ファイルの内容] )
elements.append( element )

master_ref = repo.get_git_ref( [対象のブランチ名(masterの場合は、’heads/master’)] )
master_sha = master_ref.object.sha
base_tree = repo.get_git_tree( master_sha )
new_tree = repo.create_git_tree( elements, base_tree )
latest_commit = repo.get_git_commit( master_sha )
new_commit = repo.create_git_commit( [Commitのメッセージ], new_tree, [ latest_commit ] )
master_ref.edit( new_commit.sha )

Referenceを読み解くのは、意外に調査に時間がかかりますよね。。本記事がその時間を短縮してくれることを願います。

以上です。

TravisCIでGitHubのTokenを暗号化する

TravisCIでGitHubのpagesをテストする際、GitHubのトークンが必要になります。.travis.ymlに直接書き込むと、自分のトークンを公開してしまうことになるので、暗号化して登録してみました。本記事では、その方法について記録します。

  • クライアント環境
  • GitHubトークンを入手する
  • Travis CLIのインストール
  • トークンの暗号化

クライアント環境


本記事では、以下の環境で実施しています。

  • MacOS Catalina バージョン10.15.5

GitHubトークンを入手する


GitHubトークンを入手します。

ユーザーアイコンの[Settings]から[Developer Settings]→[Personal access token]→[Generate new token]でトークンを作成します。必要な権限は以下の通りです。

  • repo
  • read:org
  • user:email

今回は入手したトークンを環境変数に設定します。

$ export TRAVIS_GITHUB_TOEKN=[入手したトークン]

Travis CLIのインストール


暗号化に必要なTravis CLIをインストールし、CLIからログインします。

以下のコマンドでTravisをインストールします。

$ gem instal travis

Travis CLIからログインします。

$ travis login --github-token $TRAVIS_GITHUB_TOEKN

デフォルトだとgithub.comにログインしにいくので、エンタープライズ版のGitHubとTravisを利用している場合は、以下のコマンドでエンタープライズ版のURLをエンドポイントに設定します。

. $ travis endpoint --set-default -X -e https://[エンタープライズ版TravisのURL]/api

トークンの暗号化


Travis CLIを利用してトークンの登録及び暗号化を行います 。詳細は公式ドキュメントをご参照ください。

GitHubのトークンを暗号化して、.travis.ymlに設定します。このコマンドは.travis.ymlが置かれているパスで実行する必要があります。

$ travis encrypt GITHUB_TOKEN=$TRAVIS_GITHUB_TOEKN -r [対象レポジトリ] --add

–addオプションによって、同一パス上にある.travis.ymlに以下を追記します。

env:
  global:
    secure: [暗号化されたToken]

最後に、.travis.ymlに暗号化したトークンをdeployブロックで指定して登録しておく必要があります。

deploy:
  github_token: "$GITHUB_TOKEN"

これでTravis CIからGitHubのテストを行うことができました。

以上です。

Ansibleでユーザーとssh鍵を指定する方法

Ansibleからサーバーに対して鍵認証でPlaybookを実行する場合、特定のユーザー名やssh鍵が必要です。例えば、AnsibleからAWSのAPI経由でEC2インスタンスを作成する場合、その後のサーバー設定作業はデフォルトのユーザ名や指定したssh鍵を利用する必要があります。本記事では、前述した要件が満たせるように、Ansibleでユーザ名とssh鍵を指定する方法について紹介します。

  • 環境
  • 事前作業
  • 引数で指定する
  • インベントリファイルで指定する

なお、公式ドキュメントではこちらで紹介されています。

環境


本記事では、以下の環境で実施しました。

サーバー:RHEL7.6
クライアント: MacOS 10.15
Ansible:2.10.5 ( python version = 3.9.1 )

事前作業


鍵認証に必要なssh鍵を生成し、サーバーとクライアントに配置します。

ssh鍵を生成する


以下のコマンドで、公開鍵と秘密鍵を生成します。パスフレーズを求められますが、今回はパスフレーズを設定しないので、Enterキーのみで設定します。

ssh-keygen -t rsa -f test_key

生成すると、秘密鍵のtest_keyと公開鍵のtest_key.pubファイルが生成されます。

サーバーに鍵を配置する


scpコマンドでサーバーに鍵を転送します。

scp ./test_key.pub root@[ホスト名]:~/.ssh/

デフォルトでauthorized_keysを確認する仕様なので、authorized_keysに鍵を登録します。

$ ssh root@[ホスト名]
→パスワードを入力
$ chmod 700 ~/.ssh
$ cat ~/.ssh/test_rsa.pub >> authorized_keys
$ chmod 600 ~/.ssh/authorized_keys
$ rm ~/.ssh/test_rsa.pub

デフォルトで鍵認証が許可されていない場合は、sshの設定ファイルを編集する必要があります。今回はrootログインを利用するので、PermitRootLoginも設定しています。

$ vi /etc/ssh/sshd_config
→以下の行をコメントアウトして保存します。
#RSAAuthentication yes
#AuthorizedKeyFile .ssh/authorized_keys
#PermitRootLogin yes

sshdサービスを再起動します。

$ service sshd restart

鍵認証でログインできることを確認する


秘密鍵を指定してログインできることが確認できたらサーバー側の設定が完了です。

$ ssh -i ./test_key root@[ホスト名]

引数で指定する


AnsibleのPlaybook実行時に引数で指定する場合は、以下のように-u--private-keyオプションを利用します。

ansible-playbook -i [インベントリファイル名] [Playbookファイル名] -u root --private-key="./test_key"

インベントリファイルで指定する


インベントリファイルで指定する場合は、以下のようにansible_useransible_ssh_private_keyを利用します。

[bastion]
"ホスト名"

[bastion:vars]
ansible_user=root
ansible_ssh_private_key_file="./test_key"

以上です。

KubernetesのCoreDNSで名前解決のログを出力する方法

Kubernetesをインストール後、Podが外部ホストと通信ができない場合、CoreDNSで名前解決できているか確認したいことがあります。本記事では、Podが外部ホストを名前解決する流れを説明すると共に、CoreDNSの名前解決のログを出力する方法を紹介します。

  • Podが外部ホストを名前解決する流れ
  • CoreDNSで名前解決のログを出力する方法

Podが外部ホストを名前解決する流れ


Podが外部ホストを名前解決する場合、デフォルト(dnsPolicyがClusterFirst)は以下の流れで名前解決します。

  1. Pod自身のlocalhostのレコードを確認
  2. CoreDNSに登録されているレコードを確認
  3. CoreDNSが稼働するサーバーで名前解決を確認

つまり、名前解決ができない場合、以下の流れで確認する必要があります。次項では、3を確認するための設定方法を記載します。

  1. PodからCoreDNSへの通信ができているか?
  2. Podの/etc/resolve.confにCoreDNSのService IPが登録されているか?
  3. CoreDNSで名前解決のログが出力されているか?
  4. CoreDNSで名前解決ができているか?
  5. サーバーで名前解決できているか?

CoreDNSで名前解決のログを出力する方法


CoreDNSのDNS設定は、以下のコマンドでConfigMapを編集することで変更できます。logを1行追加するだけで、名前解決のログを出力することができます。

$ kubectl edit cm -n kube-system coredns
apiVersion: v1
~~省略~~
data:
  Corefile: |
    .:53 {
        log ← 追加
        ~~省略~~
    }

追加すると以下のようなログが出力されるので、BusyBoxからnslookupをした時に名前解決できるか確認できます。

[INFO] 10.244.0.8:41729 - 12544 "AAAA IN [ホスト名] udp 52 false 512" NOERROR qr,rd,ra 173 0.002533234s
[INFO] 10.244.0.8:41729 - 12544 "A IN [ホスト名] udp 52 false 512" NOERROR qr,rd,ra 202 0.003439738s
[INFO] 10.244.0.8:41729 - 12544 "AAAA IN [ホスト名] udp 52 false 512" NOERROR qr,aa,rd,ra 173 0.000178813s

以上です。

マルチテナントにおけるOpenShift Service MeshによるRoute公開を検証してみた

マルチテナント環境において、OpenShift Service Meshを利用する場合の外部公開はどうすればいいか疑問を感じたので、OpenShift Service Meshを利用した場合の外部公開を検証しました。

  • OpenShiftのマルチテナント環境における外部公開(想定)
  • OpenShift Service Meshのマルチテナント環境における外部公開(想定)
  • OpenShift Service Meshの検証
    • メンバーロールの作成
    • Routeの作成
    • Gatewayの作成
  • 注意点

OpenShiftのマルチテナント環境における外部公開(想定)


マルチテナントプラットフォームにOpenShiftを採用する場合、Routeリソースを使って、それぞれのシステムを外部に公開することが想定されます。

マルチテナント管理チームがProjectリソースを作成・管理し、プロジェクトチームが各自でRouteリソースを作成することが考えられます。

※ベストプラクティスではなく、あくまでも想定です。要件・環境に応じて設計は変わることご認識いただければ幸いです。

OpenShift Service Meshのマルチテナント環境における外部公開(想定)


OpenShift Service Meshを利用する場合、Istio外部から受け付けるServiceリソースがService MeshのコントロールプレーンProjectにあります。Routeを利用して外部に公開するには、そのServiceに紐づいたRouteを作成する必要があります。

従って、RouteリソースをService MeshのコントロールプレーンProject内に作成し、各ProjectでService Meshのリソース(Gateway・VirtualService・DestinationRule)を作成する形が想定されます。

※ベストプラクティスではなく、あくまでも想定です。要件・環境に応じて設計は変わることご認識いただければ幸いです。

OpenShift Service Meshの検証


上記で想定した役割を踏まえて、実装してみました。

※VertualService/DestinationRule/Service/アプリケーションの作成は、通常のIstioと変わらないので省略しています。istio関連の操作については、Istio関連記事に投稿しています。
※OpenShift Service Meshのインストールは省略しています。インストール方法については、OpenShift Service Meshをインストールする方法に記載しています。

メンバーロールの作成


OpenShift Service Meshでは、ServiceMeshMemberRollというリソースに、Service Meshの対象プロジェクトを定義する必要があります。

以下のように、membersブロックにプロジェクト名を定義します。

apiVersion: maistra.io/v1
kind: ServiceMeshMemberRoll
metadata:
  name: default
  namespace: istio-system
  ownerReferences:
    - apiVersion: maistra.io/v1
      kind: ServiceMeshControlPlane
      name: basic-install
  finalizers:
    - maistra.io/istio-operator
spec:
  members:
    - project-a
    - project-b

Routeの作成


OpenShift Service MeshをOperatorHubからインストールすると、Istioが外部からの通信を受け付けるためのistio-ingressgateway Serviceリソースが作成されます。このServiceをRouteで外部に公開することで、クラスター外のユーザーからアクセスできるようになります。

以下のコマンドで、istio-ingressgateway に紐づくProjectAとProjectBのRouteリソースを作成します。

$ oc expose svc istio-ingressgateway --hostname=example-a.test.com --port=8080 --name=project-a --generator=route/v1
route.route.openshift.io/project-a exposed
$ oc expose svc istio-ingressgateway --hostname=example-b.test.com --port=8080 --name=project-b --generator=route/v1
route.route.openshift.io/project-b exposed

当然ながらhostnameは外部から名前解決できる必要があります。本記事ではローカルホストにexample-a.test.com, example-b.test.comを登録しました。

Gatewayの作成


各Projectで作成するGatewayを作成します。

project-aにexample-a.test.comの80番ポートで受け付けるa-gwを作成します。

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: a-gw
  namespace: project-a
spec:
  selector:
    istio: ingressgateway # use Istio default gateway implementation
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "example-a.test.com"

同様にproject-bにexample-b.test.comの80番ポートで受け付けるb-gwを作成します。

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: b-gw
  namespace: project-b
spec:
  selector:
    istio: ingressgateway # use Istio default gateway implementation
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "example-b.test.com"

example-a.test.com, example-b.test.comの名前でhttpリクエストを飛ばすと、それぞれのプロジェクトのアプリケーションに割り振られることが確認できました。

注意点


Gatewayリソースにおけるhostnameをワイルドカードにすると、期待していないアプリケーションに通信が飛んでしまうのでご注意ください。

名前解決や証明書のコントロールを考慮すると、RouteやGatewayはマルチテナント管理チームで作成・管理するのがいいのかもしれないなと感じました。

以上です。