落とし穴に立て札を立てるが如く

ハマりどころの解決が少しでも早くなることを願って書いていきます

Kubernetes をゲーム感覚で腕試しできるサイト 「Game of PODs」で遊ばないと年を越せない 2021 冬

f:id:nam_yu_sql:20211208131147j:plain
この記事は Fixer tech blog にもマルチポストしています。

tech-blog.cloud-config.jp

はじめに

最近 CKAD の受験して一旗上げようと画策しているなむゆです。
Kubernetes について学ぶ中で、腕試しに使えそうな面白そうなサイトを見つけたので紹介してみようという回です。

Game of PODs とは

Game of PODs とは、無料で遊べる Kubernetes の問題集です。
Kubernetes クラスターにアプリケーションを展開したり、クラスターで起きている問題を解決することを通してそれらの方法を学ぶことができます。
この問題集はKodeKloudというサービスに提供されている教材の一つで、KataKodaという教材用環境サービス内でホストされている仮想環境にアクセスしてハンズオン形式で課題を解くことができることが特徴です。
問題の内容としては、あるアーキテクチャが与えられて、「このアプリケーションの Pod を立ててね」「その Pod には Service を作ってこのポートでアクセスできるようにしてね」「インターネットからはこのポートでアクセスできるようにしてね」といった条件を満たした環境を作り出すことを目指すものです。
これらの条件は一つ一つクリアしていく形式ではなく、全体を作り切ってから確認ボタンを押して全体として目標を満たしているか確認する形式なので、それなりに一問の分量は多く、また、設計全体を実体に落とし込むための総合的な知識が求められます。
また、一つのアーキテクチャ全体を制限時間 1 時間の中で解く必要があるので、それなりの瞬発力も求められます。
難易度としてはそこそこ高め、Kubernetes でのリソースについて一通り理解して作成できるようになったレベルの人向けの問題集です。

始め方

Game of PODs を始めるには、まずは KodeKloud にユーザー登録を行います。
ユーザー登録できたら、以下の URL にアクセスし、「Start Course」をクリックします。
https://kodekloud.com/courses/game-of-pods/
f:id:nam_yu_sql:20211208131313p:plain
教材ページに進んだら、「Introduction」のビデオを見て概要を確認したり、「References」でハンズオンに登場するアプリケーションについての概要を眺めたのち、「Access the Game!」からワールドマップ的なページを開きます。
この中の煙が上がっている個所がそれぞれの問題の入り口になります。
f:id:nam_yu_sql:20211208131328p:plain
いずれかの個所をクリックして、「Let's fix it!」ボタンを押すと仮想環境のある KataKoda のページに遷移します。
f:id:nam_yu_sql:20211208131358p:plain
このページの下の方にある「START SCENARIO」をクリックするとしばらく仮想環境が作られるのを待ち、完了すると問題を解き始めることができます。

ただし、DATALAKE、SERVICES、INGRESS は鋭意コンテンツ作成中のようで、また、FIREWALL と PRODUCTIONCLUSTERS については現在新しいインフラに移行中のようで 2021 年 12 月 7 日現在アクセスができません。
なので、実際取り組める問題は BRAVO、PENTO、TYRO、REDISISLANDS の 4 つのようです。
難易度としては TYRO = PENTO > REDISISLANDS > BRAVO
となっているので、BRAVO あたりから始めてみましょう。

遊び方

問題を解くビューには、ターミナルとクイズポータル、そして問題の環境への外部からのアクセスリンクのタブがあります。
f:id:nam_yu_sql:20211208131447p:plain
クイズポータルのタブをクリックするとクイズポータルが開きます。ここでは、問題の中で解くべきアーキテクチャと残り時間が確認でき、左の「Check」ボタンを押すと答え合わせをすることができます。
f:id:nam_yu_sql:20211208131508p:plain
答え合わせは何度でもすることができるので、一部分ができたら毎回その部分が正しいかどうか確認するために押すといいです。
アーキテクチャ図のそれぞれの要素をクリックすると、その部分で満たすべき条件が表示されます。例えば「サービスの名前は
「サービスのタイプは
としてセットアップしてください」
「ポート番号は***で設定してください」
みたいな形です。
ターミナルではこの条件を満たすようにコマンドを駆使して設定していきましょう。

Check して全部の条件を満たすと、問題が解決できたことになります。
パスワードが表示されるので、それをコピーしましょう。
コピーしたパスワードは、KodeKloud がわのワールドマップで問題を選んだ際に表示される「Magic Chant」のテキストボックスに入力して「Submit」ボタンを押すことで登録できます。
f:id:nam_yu_sql:20211208131625p:plain
Magic Chant の内容が合っていれば煙が上がっていた部分が正常に戻ります。
やったね!

詰まったら?

どうしても詰まったら、KodeKloud の教材一覧にそれぞれの問題の解答動画があります。
わからない部分については動画で確認しながら進めるのも手です。
f:id:nam_yu_sql:20211208131638p:plain

おわりに

今回は Kubernetes の腕試し用教材の Game of PODs について紹介してみました。
Kubernetes 学習に一息つきたいときや腕試ししてみたいときにはぜひ試してみてください。

参考

普段何となく使っているレベルからもう 1 ミリだけ詳しくなる Kubernetes の Service とは何ぞや

この記事は Fixer tech blog にもマルチポストしています。

tech-blog.cloud-config.jp

f:id:nam_yu_sql:20211206083854j:plain

はじめに

Kubernetes にアプリケーションを配置するときに使用するリソースの一つに Service があります。
仕事で普段既に構成されたマニフェストを利用していると、その役割としてやっていることを忘れがちになっていたので思い出しがてら記事にしてみます。

サービスディスカバリ とは

Kubernetes の Service について説明する前に Kubernetes 上に展開したアプリケーションに対してどうやってアドレスを特定して接続を行うかを説明する必要があります。
Kubernetes 上に展開されるアプリケーションは Pod 内のコンテナとして存在しています。
そして、その Pod はそれぞれ Kubernetes クラスターのネットワーク内で指定された個別のプライベート IP アドレスを持ちます。
なので、最低限そのプライベートアドレスを知っていれば、Kubernetes クラスター内部からはアクセスが可能です。
しかし、その IP アドレスは Pod が再移動するたびに毎回変更されてしまうので、もしプライベート IP アドレスを用いて Kubernetes クラスター内で通信しようとすると接続先の Pod 再起動の度に接続先 IP アドレスの設定が必要になるので現実的ではありません。
そこで、DNS のような仕組みを作って同じ名前のアドレスにアクセスすると自動で目的の Pod にアクセスでき、しかも Pod 再起動の度に自動でアクセス先のプライベート IP アドレスを再設定してくれる仕組みがあればええやんという発想が出てきます。
この発想を「サービスディスカバリ」といいます。
直訳するとサービスを発見すること、もうちょっと意訳すると接続先のアプリケーションのアドレスを発見することになります。
そしてそれを実現するための仕組みの一つが、CoreDNS です。
これは、Kubernetes の中に仕込まれている仕組みの一つで、Kubernetes でのサービスディスカバリのデフォルトの実装となっています。
Kubernetes をインストールして起動すると、自動的に CoreDNS の pod がいくつか立ち上がり、後述の Service で規定した条件に従ってアドレスと Pod の IP アドレスの結び付けを行ってくれます。

Service ってなんぞや

そんな CoreDNS に対して、「このアドレスにやってきた通信はこっちの IP に流して!」と指示する役割を持つのが Service になります。
Service を作成するときには、そのリソースの名前と、通信の流し先の Pod の選択条件を記述します。
リソースの名前とネームスペース名から通信を受け付けるアドレスが決まります。
通信の流し先の Pod の選択条件は Service リソースの Selector として記述します。
Service で規定したアドレスにやってきた通信は、Selector の条件を満たす Pod からランダムに一つ選んで流されます。
そうです、Selector では通信の流し先の Pod の選択条件を規定するので、その条件に合う Pod は一つとは限りません。
複数の Pod が条件に当てはまればその条件に当てはまる Pod にほぼ平等に通信を分配するので、同じ Pod を複数用意しておけばその間でロードバランシングのようなこともできます。
その他、標準的な方法ではないのですが、Service では Kubernetes クラスター内からリクエストだけでなくクラスター外部からやってきたリクエストを Node のポート番号を指定して受け入れることもできます。
とはいえ、この方法だけだとインターネットからアクセスする際のアドレスは kubernetes クラスターに属するそれぞれの node のパブリック IP アドレス+ポート番号になってしまうので、アプリケーションを外部公開する際には素直に「Ingress」という別の仕組みを使うのが吉です。

おわりに

今回は思い出しがてらに Kubernetes の基本的な構成要素の Service についてその役割ややっていることについて説明しました。
知っている人にとっては当たり前のこと鳴きもしますが、復習がてらドキュメントを読み直してみるのも役に立つかと思います。

参考

明日 Kubernetes が少し楽しくなる認証の話

この記事はcloud.config tech blogにもマルチポストしています。

tech-blog.cloud-config.jp

はじめに

この記事を読んでいる方は、普段 Kubernetes をどのように利用しているでしょうか。
多くの方が、アプリケーションのデプロイを日常的に行っているか、あるいはその処理を自動化する作業を日々行っていると思います。
アプリケーションをデプロイすると、当たり前のように Pod が展開されて動き始めますが、その後ろでは普段気にしなくても様々なパラメータが扱われており、それを使って処理が行われています。
そのことをそこまで深く知らなくても Kubernetes を扱うことができますが、知るともう少しだけ Kubernetes を深く知り、アプリケーションを展開するときに「あ~今頃 Kubernetes ではこんなことが起きてるんだな~」と思えるようになります。
今回はそんなお話、Pod が立ち上がるたびにやりとりされる認証関連のお話です。

Kubernetes には2種類のアカウントが居る

実は、Kubernetes には 2 種類のアカウントが居ます。
一つは、普段 Kubernetes 外部からユーザーが Kubernetes を操作するために使うユーザーアカウントです。
これは、ユーザーが Kubernetes を操作する際にその操作を行っていいかの認可処理や、そもそもその操作をしようとしているユーザーが何者かを認証するために使用されます。
ユーザーアカウントの認証はローカルに置かれている ~/.kube/config にある kubeconfig ファイルの中にあるクライアント証明書というものを用いて行います。

users:  
- name: docker-desktop  
  user:  
    client-certificate-data: <クライアント証明データ>  
    client-key-data: <クライアントキー>  

上は docker-desktop にアクセスする際のクライアント証明書です。
Kubernetes にアクセスするときは上記のデータを Kubernetes 側に渡して、自分が何者であるか証明し、割り当てられている権限を用いて操作を行います。

2 種類のアカウントのうちもう一つは、サービスアカウントです。
こちらは、Kubernetes 内部のプロセスが使用するアカウントになります。
サービスアカウントは Namespace 毎に作られます。
そして、サービスアカウントが作られると、その資格情報としてトークンがSecret内に作られます。
つまり、作りたてほやほやの Namespace にも Secret とサービスアカウントが一つずつ作られています。

ローカルの Kubernetes で試してみましょう。
「そもそもローカルに Kubernetes 仕込んでないよ・・・」という方はこちらの記事を参考にしてローカル PC に Kubernetes を仕込んでみてください。
意外と簡単です。

kubectl create Namespace sample  

上記のコマンドで Namespace を新規作成します。

kubectl get serviceaccount, secret  

次に、上記のコマンドを実行して serviceaccount と secret のリソースの一覧を取得します。
結果は以下のようになるはずです。

NAME                     SECRETS   AGE  
serviceaccount/default   1         11d  
serviceaccount/sample1   1         2d  
  
NAME                         TYPE                                  DATA   AGE  
secret/default-token-8g2zb   kubernetes.io/service-account-token   3      11d  
secret/sample1-token-5b9pr   kubernetes.io/service-account-token   3      2d  

それぞれのリソースに、sample1 という名前のサービスアカウントと Secret が追加されています。
さらに、それとは別に「default」という名前のサービスアカウントと Secret も見えます。
こちらは、Namespace がまだ一つも手動で生成されていないときに自動で生成される Namespace で、Namespace を指定せずに作成されたリソースは全部 default の Namespace に作られます。

このように、namespace を新規作成するとそのたびに Secret とサービスアカウントが生成されます。

実は全部の Pod はサービスアカウントの資格情報を持っている

Kubernetes が動いているマシンの中で動いている Pod のプロセスも Kubernetes それ自体と通信することがあります。
ただ、Kubernetes と通信を行って何かしら操作しようとするマシン内のプロセス全部が Kubernetes のものとは限りません、ひょっとしたら何かしら悪意のあるプロセスがマシン内で動いていて Kubernetes を乗っ取ろうとしているかも?
ということで、プロセス側がそのような悪意のあるものでないと証明するのに使うのがサービスアカウントです。
Pod それぞれにサービスアカウントの資格情報を持たせることで、その Pod から kubernetes への通信に資格情報を含めて送ることでその通信がちゃんとした kubernetes のプロセスのものであると証明しています。
なので、全ての Pod は実はサービスアカウントの資格情報を持っているのです。
「え、これまで Pod 作るときにサービスアカウントの資格情報とか渡してないんだけど・・・」と思うかもしれませんが、大丈夫です、資格情報は指定しなくても自動的に default サービスアカウントのものが Pod に渡されています。

確認してみましょう。

kubectl run nginx --image=nginx  
kubectl get pod nginx -o=yaml  

すると、get pod コマンドを打った結果の大量の出力の中に次のような行があるかと思います。

  serviceAccount: default  
  serviceAccountName: default  

このように、サービスアカウントとしては Pod の生成時に明示的に指定しなくても、自動的に default のものが割り当るようになっています。
あるいは、サービスアカウントを作成してこれらのパラメータに設定することで明示的に「これを使って!」と宣言することもできます。
デフォルト以外のサービスアカウントを設定する目的としては、RBAC を用いて Pod 毎に厳密に権限をコントロールすることが挙げられますが、普段はあまり気にしないかもです。

おわりに

今回の記事では kubernetes の中で実は暗黙的に行われている認証の話について語ってみました。
ユーザーが認証、認可を受けて kubernetes とやりとりしているように、個々の Pod も認証、認可を行って kubernetes とやりとりしています。
これらの設定については普段触らなくても暗黙的にやってくれているものですが、知っておいて損はないかと思います。
明日からは「あ~今 kubernetes の中ではそれぞれの Pod にサービスアカウントが割り当っててそのおかげで Pod のプロセスが kubernetes とやりとりできているんだな~」と思いながらアプリケーションをデプロイしてください。

参考

今更ながら学ぼう kubernetes での Pod の立て方

この記事はfixer tech blogにもマルチポストしています。

tech-blog.cloud-config.jp

f:id:nam_yu_sql:20211201150118j:plain

はじめに

これを読んでいる方は普段 kubernetes で Pod 立てるときどんなふうに立てているでしょうか?
多くの場合、既に作成されているマニフェストファイルを共有されて、それを一部書き換えて apply するやり方をしているのではないかと思います。
それはそうすることで作成する kubernetes リソースをスクリプトとして管理できるという便利な側面があるからなのですが、一方でその後ろで行っていることの理解はしづらくなることもあるかと思います。
普通にアプリケーションを kubernetes 環境にデプロイする業務をするにはそこまで深く理解しなくても問題ないのですが、その後ろでどのようにして Pod が立っているか理解したくなっている気分の方はこの記事を読んでみてください。

そもそも Pod ってなんだ

Pod の概観
kubernetes での Pod というのは、アプリケーションのデプロイができる最小単位のリソースです。
この中には、一つまたは複数のコンテナが動いています。
コンテナというのは・・・・・
それぞれの中でアプリケーションなどが動いている環境です。
今回はコンテナについてはこれ以上掘り下げません。
kubernetes ではアプリケーションをコンテナ単位で動かすことはできず、アプリケーションをデプロイするということはほぼイコール Pod をデプロイするということになります。
ただ、Pod をデプロイする方法が kubernetes にはいくつか用意されており、それによって同時にデプロイされるリソースや機能が変わってきます。
以下ではその種類について解説します。

Pod の立て方その 1、Pod をそのまま立てる

Pod をそのまま立てる方法です。
Pod を立てるにはマニフェストファイルを作成してそれを apply する方法もあるのですが、Pod を立てることそれ自体はコマンド一つで実行できます。
今回は nginx のコンテナが一つ動く Pod を作成します。

kubectl run nginx --image=nginx  

実行が成功したら、以下のコマンドで作成されたリソースを確認してみましょう。

kubectl get all  

コマンドの出力としては、以下のようなものになるはずです。
Pod のリソースができました。
これが、Pod をそのまま立てる方法になります。

NAME        READY   STATUS    RESTARTS   AGE  
pod/nginx   1/1     Running   0          67s  

確認出来たら、今回作成した Pod は以下のコマンドで削除できます。

kubectl delete pod nginx  

Pod の立て方その 2、ReplicaSet を立てる

ReplicaSet
次は、ReplicaSet と呼ばれるリソースを作成する方法です。
この方法はコマンドだけで実行することはできず、マニフェストファイルの作成が必要になります。
新しい yaml ファイルを作成し、以下のコードを書き写して保存します。

apiVersion: apps/v1  
kind: ReplicaSet  
metadata:  
  name: nginx-replica-set  
  labels:  
    app: nginxReplicaSet  
spec:  
  replicas: 3  
  selector:  
    matchLabels:  
      app: nginxPod  
  template:  
    metadata:  
      labels:  
        app: nginxPod  
    spec:  
      containers:  
        - name: nginx  
          image: nginx  

保存出来たら、以下のコマンドで作成したマニフェストを apply し、kubernetes 上にリソース作成を指示します。

kubectl apply -f <作成したマニフェストファイルのパス>  

コマンドの実行が成功したら、以下のコマンドを実行してどのようなリソースが作成されたか確認してみましょう。

kubectl get all  

結果としては以下のようなものになるはずです。(STATUS 等は状態によって変わるかと思います。)
マニフェストファイルで定義したのは ReplicaSet のみですが、その定義の中にある template の内容に従って、Pod のリソースも同時に作成されています。
ReplicaSet は同じ Pod が常に複数立っている状態を維持してくれるリソースで、これが生きている限り template で指定した設定の Pod の個数をreplicas:のパラメータで指定した個数に保とうとしてくれます。
この働きによって、ReplicaSet のリソースを作成するとその ReplicaSet によってコントロールされている Pod が個別にコマンド実行することなく自動生成されます。
なので、ここで例えば作成されている Pod を一つ削除したりすると、すぐに新しい Pod が立ち上がってきて頭数を合わせてくれます。

NAME                          READY   STATUS              RESTARTS   AGE  
pod/nginx-replica-set-fb9vq   0/1     ContainerCreating   0          9s  
pod/nginx-replica-set-hz2cb   1/1     Running             0          9s  
pod/nginx-replica-set-zxxfp   1/1     Running             0          9s  
  
NAME                                DESIRED   CURRENT   READY   AGE  
replicaset.apps/nginx-replica-set   3         3         2       9s  

今回作成した ReplicaSet は以下のコマンドで削除できます。
ReplicaSet を削除すると、コントロールされていた Pod も同時に削除されます。

kubectl delete replicaset nginx-replica-set  

Pod の立て方その 3、Deployment を立てる

Deployment
3 つ目の方法は、Deployment を立てる方法です。
Deployment を立てることによっても Pod が立ちます。
Deployment についてはマニフェストを実行する以外にもコマンド一つで立ち上げる方法があります。

kubectl create deployment nginx-deployment --image=nginx --replicas=3  

コマンドが成功したら、どのようなリソースが作成されたか見てみましょう。

kubectl get all  

コマンドの事項結果は以下のようなものになるはずです。
今回立てた Deployment のほかに、Pod、さらに先程は手動で作成していた ReplicaSet も自動生成されています。
この Deployment というリソースは、Pod のデプロイ周りをコントロールしてくれるリソースで、デプロイされている Pod の個数を維持するために、Pod だけでなく ReplicaSet もコントロールします。
Pod の個数を維持するだけであれば ReplicaSet で十分な気もしますが、Deployment にはもう一つ別の機能があります。
それは、アプリケーションの更新時に Pod を止めずに更新することです。
例えば、Deployment 作成のコマンドの image を nginx から redis に更新して実行すると、Pod を全部削除せず、新しい Pod を作成しながら一部分だけ削除して全体を置き換えていくような動きをします。
これによって、例えば Pod で動かすコンテナのバージョンを上げた際にアプリケーション全体を止めることなく、更新をかけることができます。
ReplicaSet だと、例えばマニフェストファイルの中の image を redis に変えて実行するとそれだけだと Pod の更新が行われません。
更新するには、Pod を手動で削除して置き換えていく必要があります。
Deployment だとそのあたりもコントロールしてくれます。

NAME                                    READY   STATUS              RESTARTS   AGE  
pod/nginx-deployment-84cd76b964-578g2   1/1     Running             0          8s  
pod/nginx-deployment-84cd76b964-bf67f   0/1     ContainerCreating   0          8s  
pod/nginx-deployment-84cd76b964-j2ltp   1/1     Running             0          8s  
  
NAME                               READY   UP-TO-DATE   AVAILABLE   AGE  
deployment.apps/nginx-deployment   2/3     3            2           8s  
  
NAME                                          DESIRED   CURRENT   READY   AGE  
replicaset.apps/nginx-deployment-84cd76b964   3         3         2       8s  

この辺りのことを弄り終わったら、以下のコマンドで deployment を削除できます。
deployment を削除すると、自動的に ReplicaSet も Pod も削除されます。

kubectl delete deployment nginx-deployment  

おわりに

今回は、Pod をデプロイするということについて、kubernetes の機能を段階的に紹介しました。
一般的には Pod をデプロイする際には Deployment リソースをデプロイしていると思います。
なぜなら、レプリカ数の設定による可用性の維持や、更新時にもアプリケーションの動作を止めないようにすることなどは Web アプリとしては目指すべきところである上にコストもほとんどかからないためです。
ただ、その後ろでは ReplicaSet が立って、さらにそれが Pod を立てて・・・みたいなことをやっていることを知ることで、kubernetes についてもう一段深く知ることができるのではないかと思います。

参考

Azureの資格試験「DP-100」を取得したので合格者の視点から語ってみる

f:id:nam_yu_sql:20210712072106j:plain この記事はcloud.config tech blogにもマルチポストしています。

tech-blog.cloud-config.jp

はじめに

マイクロソフト資格MCPにはRoleに合わせた様々なものがあるのですが、その中には機械学習系のRoleに関するものもあります。
以前から気になってちょくちょく勉強したりしていたのですが、最近ついに受験して合格してきたので、今回はそのDP-100という試験について共有したいと思います。

DP-100ってどんな試験?

公式サイトこちらです。
AzureのAI、機械学習系のサービスに関する資格試験の一つで、特にAzureのサービスを使って機械学習を用いたモデリングや分析を実際に行う方法に関する理解度を問われます。
機械学習の分析手法のことだけでなく、モデリングに使用するマシンの用意の方法から作成したモデルの運用まで、データサイエンスの業務のフロー全般が試験範囲になっています。
似た分野の試験はいくつかあります。例えば、AI-900という試験は人工知能機械学習の全般的なトピックを扱っています。特にAzure Bot ServiceやQnA Maker、Cognitive Serviceを用いた人工知能系のサービスに重点が置かれています。
他には、DP系試験の中にDP-203という試験があったりするのですが、こちらは機械学習そのものというよりは、機械学習に使用するためのデータの扱いが焦点となっています。
Azure SynapseやDatabricksを使用して様々な種類の大量のデータをどのように扱うかといった内容が試験範囲になっており、分析それ自体よりも機械学習で使用するためのデータの扱い方に興味がある方はこちらの方が向いているかもしれないです。
DP-100はそれらの中では機械学習の分析を行う方法の周りに焦点が置かれているのが特徴といえます。

DP-100ってどんな人向け?

Azureの機械学習系サービスに興味がある人、あるいはそれらを用いて業務を実際にこなしている人。
機械学習と言っても分析することだけでなく、マシンリソースの話から作ったモデルを運用するところまで含めて興味がある人向けの試験のように思います。
人工知能の分野も含めるとAI-900も候補に挙がりますが、チャットボットを作ったり画像内の物体検知したり云々というよりはデータを基にしてモデリングを行い、知見を抽出するデータサイエンスのトピックに興味がある人はDP-100が向いているように思います。
あるいは、次章のトピックを眺めてみて面白そうだったら受けてみるという決め方もいいかもしれません。

出題範囲のトピック色々

出題範囲は、サービスとしてみるとAzure Machine LearningサービスとDatabricks周りがメインになるのですが、機械学習系の業務のフローで見ると大きく分けて分析前の下準備の話、モデリングの話、モデリング後のデプロイや運用の話の3つくらいに分けられるように思います。
今回もその中で個人的におもしろそうだと思ったトピックをピックアップしていきます。
気になった部分がある方は、試験ページのLearnから、対応するトピックを探してみてください。

下準備

  • データの取得元の話。SQL Database、Databricks、Azure Storage等に配置したデータを分析対象にしたり。
  • データには欠損値や偏りがありがち。その解消方法とか。
  • 機械学習には分析のための高性能なマシンが必要。その設定方法とか。
  • 大量のデータを扱うのに使えるDatabricksというサービスのお話。

機械学習モデリング

デプロイ&運用

  • 作ったモデルはaksクラスターにWebアプリとしてデプロイして利用することができる。そのやり方とか。以前記事にも書きました。
  • いわゆるMLOpsの話。一度デプロイしたモデルを、時間の経過とともに更新して新しいデータに対しても精度を落とさないようにするには?
  • Application Insightsと連携してデプロイしたWebサービスからメトリックを出力し、運用状況を監視したり。

おわりに

今回は、最近試験を受けて合格したMicrosoft試験のDP-100について語ってみました。
この資格の試験範囲はAzureを使って実際にどういったやり方で機械学習を行うのかを学ぶのに一番適しているように思います。
興味が出たら、実際に試験を受けないでも、試験ページの下にある試験範囲に対応したLearnを見て興味のある分野について学んでみてください。

参考

Azure DevOpsでTerratest使ってTerraformスクリプトのテスト自動化をしましょーよ!の会

f:id:nam_yu_sql:20210518081229j:plain

この記事はcloud.config tech blogにもマルチポストしています。

tech-blog.cloud-config.jp

はじめに

最近はTerraformも回しています、なむゆです。
IaCを実現するツールであるTerraformですが、そのコードを編集した際にちゃんと思った通りに動くか確認する方法としては、そのコードを実際に動かして作成された環境を確認するのが一般的かと思います。
しかし、そうすると毎回terraform planしてterraform initし、環境が作成されて動作確認もできたら手動でその環境を削除しなければならず、かなり手間と時間がかかります。
ここを効率化しようとしたときに使えそうなツールをいろいろ探していた時に見つけた方法として、今回はTerratestを用いたAzure DevOpsパイプラインを作る方法を共有したいと思います。

Terratestとは

Terratestは、Gruntwork.ioが開発している、インフラストラクチャー向けのGo言語のテストライブラリです。
terra---という名前のとおり、terraformをメインでサポートしていますが、他にPackerやDocker、Kubernetesの構築のテストも行えるようです。
特に、terraformをサポートしているため、terraformがサポートしているGCPAWS、そしてAzureのインフラもテストすることができます。

TerratestをAzure Pipelineで実行出来たら何がうれしいの?

そんなインフラのテストライブラリであるTerraformですが、CI(継続的インテグレーション)の仕組みとしてAzure Pipelineに組み込めるとさらに強力になります。
Azureの環境構築にTerraformを使っていた場合、そのTerraformスクリプトGithub等で管理するかと思うのですが、更新したときにはそのコードをマージしても動作することを保証するために動作確認を取るかと思います。
その際にTerratestを使ったパイプラインを用意することで、例えばGithubにPRが作成されたタイミングでTerratestによるテストを自動的に実行し、動作確認を取って結果が正常かどうかを確認することができます。
手動で動作確認を取ろうとすると環境作成の手順や作成したリソースの確認の手間がかかったり作業した箇所以外の影響に気付かずデグレが起きたりする可能性がありますが、テストとして動作確認の自動化の仕組みを作っておくことでこれらを解決できます。

実際にTerratestのテストパイプラインを作ってみる

ここではTerratestのサンプルスクリプトを使いながら、Azure DevOpsのパイプラインとしてAzureにリソースをデプロイするTerraformスクリプトのテストを行う例を示したいと思います。

スクリプトを用意

今回使用するTerraformとテスト用のgolangスクリプトはTerratestのExamplesのページにあるAzureの例のものになります。
4つあるので、これらをAzure DevOpsのReposなり、権限のあるGithubリポジトリなりに作成しておきます。
気を付ける必要があるのはこれらを配置するディレクトリ構成です。
terraform_azure_example_test.goからの相対パスの記述の都合上以下のような構成で配置するようにしてください。

├─examples  
│  └─azure  
│      └─terraform-azure-example  
│              main.tf  
│              outputs.tf  
│              README.md  
│              variables.tf  
│  
└─test  
    └─azure  
            terraform_azure_example_test.go  

それに加えて、パイプライン用の以下のyamlスクリプトリポジトリ内の適当な場所に作成しておきます。
テスト用のgoスクリプトがあるディレクトリのパスだけ実際のディレクトリに合わせて変更しましょう。

pr: main  
trigger: none  
  
variables:  
  - group: AZURE_CREDENTIALS  
  
steps:  
  - pwsh: |  
      az login --service-principal -u $(ARM_CLIENT_ID) -p $(ARM_CLIENT_SECRET) --tenant $(ARM_TENANT_ID)  
      az account set --subscription $(ARM_SUBSCRIPTION_ID)  
      cd $(Build.SourcesDirectory)/[ここにはソースのルートディレクトリからテスト用のgoスクリプトがあるディレクトリまでのパスが入ります]  
      go mod init "terratest-ex"  
      go get -v -u github.com/gruntwork-io/terratest  
      go test -v -timeout 30m  
    env:  
      ARM_CLIENT_ID: $(ARM_CLIENT_ID)  
      ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)  
      ARM_SUBSCRIPTION_ID: $(ARM_SUBSCRIPTION_ID)  
      ARM_TENANT_ID: $(ARM_TENANT_ID)  

今回使用するスクリプトとしては上記のもので全部になります。
次はこれらのスクリプトを動かすための下準備をしていきます。

Azureのサービスプリンシパルを用意

この作業には、お手持ちのAzure サブスクリプションに対して権限を割り当てられたサービスプリンシパルが必要になります。
所有者権限があれば十分なので、サービスプリンシパルを作成し、サブスクリプションに対して権限を割り当てておきます。
具体的な方法についてはこちらのドキュメントを参考にすると分かりやすいかと思います。
この時、いくつかのパラメータをメモしておくようにしてください。
パイプライン実行時にterraformの実行対象のサブスクリプションへのログイン処理に必要になるためです。
必要なものとしては、「割り当てた対象のサブスクリプションのID」「作成したサービスプリンシパルのクライアントID」「サービスプリンシパルを作成したActiveDirectoryのテナントID」、「作成したサービスプリンスパルにログインするためのシークレット」の4つになります。
サービスプリンシパルのシークレットの作成については、上記のドキュメント内の「新しいアプリケーション シークレットを作成する」の項にやり方が書かれています。

Variable Groupを用意

パイプラインで使用するVariable Groupを用意します。
Azure DevOps内のPipelines -> Library -> 「+ Variable Group」のボタンから、VariableGroupを新規作成します。
Azureのサービスプリンシパルを用意する際に取得した4つのパラメータをそれぞれの名前で追加していきます。

ARM_CLIENT_ID: 作成したサービスプリンシパルのクライアントID  
ARM_CLIENT_SECRET: 作成したサービスプリンスパルにログインするためのシークレット  
ARM_SUBSCRIPTION_ID: 割り当てた対象のサブスクリプションのID  
ARM_TENANT_ID: サービスプリンシパルを作成したActiveDirectoryのテナントID  

これら4つの変数を追加出来たら、Variable group nameに「AZURE_CREDENTIALS」と名前を付けて保存します。

パイプラインを用意

これにて下準備は完了したので、パイプラインを用意します。
パイプラインの作成方法については過去記事に例があるのでそちらを参考にしてみてください。

実行

最後に作成したパイプラインを実行します。
このパイプラインは6分程度で完了するかと思います。
処理の途中でAzureを開くと、リソースが作成されていることが確認できるかと思います。
そして、テストが終わるとそのテストのために作成されたリソースが順次削除されていき、最終的にはテストの実行前の状態に戻ることが確認できるかと思います。

おわりに

今回はAzure DevOpsでTerratestを用いたTerraformのコードのテストを実行する方法を共有しました。
これによってTerratestでのTerraformスクリプトのテストをAzure Pipeline上の自動化されたタスクとして行えるようになります。
Terraformコードが本当に動くか確認するために実際にterraformを実行して目視で動作確認するスクリプトて、テストに書いてあることはより確実にチェックでき、変更による他の部分の予期しない影響も感知することができます。
また、今回は行いませんでしたが、terraformスクリプトをapplyするのではなくplanをした際の結果を用いてテストを行うこともでき、そちらの方法だと1回のテストにかかる時間が少ない分より頻繁にテストを実行することができます。

Terraformコードの動作確認の効率化をしたい際に検討してみるのもいいかと思います。

参考

Azure Pipeline のパイプラインのトリガーの設定値はちゃんと明示的に書くんよ~

f:id:nam_yu_sql:20210425080324j:plain この記事は cloud.config tech blog にもマルチポストしています。

tech-blog.cloud-config.jp

はじめに

相変わらずパイプラインを回しています、なむゆです。
今回は、Azure Pipeline でパイプライン作成時に遭遇したパイプラインの実行条件のネタで一席打ちます。

パイプライン yaml のトリガーの話

Azure Pipeline とは Azure DevOps に含まれるサービスの一つで、CI/CD のためのパイプラインを作成し、実行できます。
Github 等のバージョン管理システムと連携することができ、設定さえしておけば Github 上のリポジトリにコードを push するだけで反射的にパイプラインを実行し、アプリケーションをビルドしたり(Continuous な Integration)、ビルドしたアプリを各種実行用の環境にデプロイしたり(Continuous な Delivery)することができる、CI/CD の概念を実現するためのサービスです。
Azure Pipeline を用いて CI/CD のためのパイプラインを実行する際にはそのパイプラインで行うことを指定するパイプライン yaml というものを書くのですが、その例や中身のざっくりした意味合いについては、こちらの記事で一つの例を解説しています。
今回は、この中では trigger: none とか pr:noneとなっている部分の話です。

これらの行は何を設定しているかというと、そのパイプラインが実行される条件です。
CI トリガー、PR トリガーと呼ばれています。
パイプラインを実行するためのトリガーにはほかにもいくつか種類があるのですが、今回はこれらの 2 つのトリガーで起きることを解説するため、他の種類のトリガーの解説については割愛します。

CI トリガー

まず、trigger: で始まるセクションは、CI トリガーというものを設定します。
これは、githubリポジトリ等の特定のブランチにコードが push された際、それをトリガーにしてパイプラインを回す設定です。
例えば ↓ のような書き方をします。

trigger:  
  branches:  
    include:  
    - '*'  
    exclude:  
    - feature/*  

この例の意味合いとしては、「基本的にどのブランチにコードが push されてもこのパイプラインを実行するよ~(*は全ブランチを示す)、でも feature/下のブランチにはコードが push されてもパイプラインを回さないよ」というものになります。
include:の下にあるブランチ名の配列がそのブランチにコードが push された際にパイプラインを実行する条件で、excludeの下にあるブランチ名の配列は include の条件で判別した後でやっぱりパイプラインを実行しない場合を指定する条件になります。

簡略な書き方としては、コードの push でトリガーする対象のブランチだけを指定するものもあります。

trigger:  
- main  
- releases/*  

上記の例では、main ブランチと release ブランチについてはコードが push されればパイプラインを実行しますが、他のブランチであれば実行しなくなります。

PR トリガー

次は、pr:で始まるセクションについてです。
こちらは PR トリガーというものを設定しています。
PR トリガーは、Github で PR が作成された際にパイプラインを実行するトリガーです。
例えば PR 作成時に単体テストを実行するなどといったことをするために使用します。

こちらは ↓ のような書き方をします。

pr:  
  branches:  
    include:  
    - main  
    - releases/*  
    exclude:  
    - releases/old*  

意味合いとしては、PR 作成時にパイプラインが実行されるということ以外 CI トリガーのものと基本的に同じです。
こちらにも、CI トリガーと同じように簡略化した書き方があります。

pr:  
- main  
- releases/*  

パイプラインのトリガーを設定しないとトリガーの対象が全てのブランチになる

Azure Pipeline のパイプライン yaml ではパイプラインの振る舞いを定義する様々な値を設定することができます。
その中のたいていのものは必要なければ設定を書かなければ何も起きず、パイプラインへの影響もありません。
しかし、その中で一部、何かしら値を設定しておかないと思っていたものと違う動作をする値があり、その例が CI トリガーと PR トリガーになります。

基本的にどの値も yaml の中に明示的に記述しなければ暗黙的にデフォルトの値が設定されるのですが、それが CI トリガーと PR トリガーでは以下のようになります。

trigger:  
  branches:  
    include:  
    - '*'  
pr:  
  branches:  
    include:  
    - '*'  

つまり、デフォルトではどのブランチにコードが push されても、どのブランチにマージしようとする pr が作成されてもパイプラインが実行されることになります。

これだと、例えば何かしら常に手動でのみ回したいパイプラインがあった時、CI トリガーと PR トリガーが必要ないやと思って何も書かないでいると、どこかしらのブランチにコードが push され、PR が作られるたびに勝手にパイプラインが実行されるようになります。
例えば手動でしか回したくないような重くて長時間かかるような処理をパイプラインとして実行していた場合、コードの push のたびにパイプラインが実行され、Organization で確保していた Pipeline 用の Agent の枠を圧迫するようになってしまいます。
そういった事態は避けたいですよね。
なので、CI トリガーと PR トリガーは、使用しない場合は明示的に書いてやる必要があります。

trigger: none  
pr: none  

このように書いておくと、コードの push や PR の作成をトリガーとしてパイプラインが実行されなくなるので、手動でのみ実行できるパイプラインになります。

おわりに

今回の記事では Azure Pipeline のトリガー設定は使用しない場合は明示的に使用しないことを記述しないと常に使用する状態になってしまうことを共有しました。
たぶんこの記事を読んでいる方は手動で回したりタイマーでトリガーするパイプラインが時々勝手に回っていることに悩んでいるのかなと思うので、その方向けの対処法を説明しました。
同じような問題を抱えている方の助けになれば幸いです。

参考