見出し画像

Azure で CI/CD を体験してみよう!そう、Azure DevOps!

さて、昨今注目の DevOps やアジャイル開発、これからの時代ますます重要になってきますが、それらを実現する現実的な手法としてよく聞く単語 『 CI/CD 』 ってソフトウェア開発などに関わっていないとなかなかピンとこないですよね?

CI =
Continuous Integration ( 継続的インテグレーション )
CD =
Continuous Delivery ( 継続的デリバリー )
or
Continuous Deployment ( 継続的デプロイメント )

となりますが、「 継続的 」はわかるとして

インテグレーション? デリバリー? デプロイメント?

ってなりますよね?
これらをもうちょっとかみ砕いて言うと、

「 ソースコード(ソフトウェア開発やインフラの構成コード)に変更(修正)を加えると、それをきっかけにそのコードをビルド(実行ファイルに変換)してテストして、運用しているシステムの任意の環境に配置する 
という一連の流れを自動化すること

となります。

自動化というのがポイントで、これにより工数削減となりさらに言えば属人性の排除やヒューマンエラーを排除し、開発してから実際にサービスとして提供するまでのリードタイムを短縮できるのです。

この手法を使わない場合と比べて、バグ修正や機能追加などガツガツ行っていけるのでユーザーはもちろん、ITエンジニアにとってもありがたい仕組みです。
ちなみに、この仕組みのことを『 CI/CD パイプライン 』と言います。

ということで、この記事では

Azure のサービスを使って、CI/CD パイプラインの構築から実際の動作までご紹介しようと思います。

---  概要  ---

PHPのアプリケーションコードに変更を加え、その変更を自動でデプロイ先のWebサーバーに反映させる

ということを行います。
使用する Azure の主なサービスは、

🔹App Service
🔸Azure DevOps

となります。

🔹App Service は、AWSでいうところの Elastic Beanstalk で、Webサーバーのマネージドサービスです。

Azure App Service は、Web アプリケーション、REST API、およびモバイル バックエンドをホストするための HTTP ベースのサービスです。 開発には、.NET、.NET Core、Java、Ruby、Node.js、PHP、Python のうち、お気に入りの言語をご利用いただけます。 アプリケーションの実行とスケーリングは、Windows ベースの環境と Linux ベースの環境の両方で容易に行うことができます。

公式ドキュメント:App Service の概要

🔸Azure DevOps 
    - Azure Repos
    - Azure Pipelines
    - Azure Boards
    - Azure Test Plans
    - Azure Artifacts
で構成される CI/CD パイプライン提供サービスです。

Azure DevOps には、作業の計画、コード開発の共同作業、およびアプリケーションのビルドとデプロイを行うためのサポートチーム向けの開発者向けサービスが用意されています。 Azure DevOps は、開発者とプロジェクトマネージャーおよび共同作成者をまとめてソフトウェア開発を完了するための、カルチャとプロセスのセットをサポートしています。 これにより、組織は従来のソフトウェア開発アプローチよりも迅速に製品を作成し、改善することができます。
公式ドキュメント:
Azure DevOps とは

公式ドキュメントを見ていただくと、各サービスの関係性がイメージできると思います。

画像63

出典:Azure DevOps を使用した CI/CD パイプラインの設計

🟢 事前準備 🟢

①アプリケーションデプロイ環境作成

文字列で検索をしても良いですが、「すべてのサービス」➡「Web」➡「App Service」と Azure Portal から探してみてください。

画像1

で、そこから条件を指定して作成していきます。
今回は、PHPのコード(アプリ)を Linux上にデプロイすることにしました。

画像2

ちなみに、『 App Service プラン 』というのはデプロイするアプリケーションの実行環境となるリソースのことです。
自動的に新規作成のものが選ばれますので、このままにします。
「 SKU とサイズ 」はとりあえず何も考えず『 Standard S1 』を選択してください。

画像3

App Service (Web Apps、API Apps、または Mobile Apps) では、アプリは常に App Service プラン で実行されます。 また、Azure Functions には、App Service プラン で実行するオプションもあります。 App Service プランでは、Web アプリを実行するための一連のコンピューティング リソースを定義します。 これらのコンピューティング リソースは従来の Web ホスティングの "サーバー ファーム" に似ています。 1 つまたは複数のアプリを同じコンピューティング リソース (または、同じ App Service プラン) で実行するように構成することができます。
公式ドキュメント:Azure App Service プランの概要

デプロイ、監視、はデフォルト値で問題なく、タグはお好みに応じてつけてください。

デプロイ監視タグ

App Service 関連のリソースの作成が完了したら、ステージング スロット用の 『 デプロイスロット 』 を作成します。
運用スロット

以下のように、『 staging 』という名前で作成します。

スロットの追加

作成が完了すると、『 運用スロットの名前 + staging 』という名前で作成されたことが確認できます。

画像8

そして、今回作成されたリソースを見てみると、以下の三つのリソースが作成されていることが確認できます。

画像9

💡補足

今回は、追加のデプロイスロット(ステージング環境)を使って、Webアプリケーションの環境切り替え(スワップ)をしようと思います。
実行している App Service プランのサービス レベルが Standard、Premium、または Isolated である場合は、Web アプリ、Linux 上の Web アプリ、モバイル バック エンド、または API アプリを Azure App Service にデプロイするときに、既定の運用スロットではなく別個のデプロイ スロットを使用できます。 デプロイ スロットは、固有のホスト名を持つライブ アプリです。 アプリのコンテンツと構成の各要素は、(運用スロットを含む) 2 つのデプロイ スロットの間でスワップすることができます。

公式ドキュメント:
Azure App Service でステージング環境を設定する

こういったことを行う場合、App Service プランの『 SKUとサイズ 』を適当に選択して作成してしまうとできません。Standard、Premium、Isolated のいずれかでなければならないです。

なので今回は、『 Standard S1 』を選択しました。

画像6

②Azure DevOps Organizations 作成

こちらについても、文字列で検索をしても良いですが、「すべてのサービス」➡「DevOps」➡「Azure DevOps Organizations」と Azure Portal から探してみてください。

画像10

以下のページに遷移したら、『 My Azure DevOps Organizations 』 をクリックします。

画像11

『 新しい組織の作成 』 をクリックします。

新しい組織の作成

そして、組織名を決める必要があるので任意の名前を付けてください。

組織の名前

あと、プロジェクトの作成が必要になります。
今回は、Private の 『 test-project 』 としました。

プロジェクト作成

作成が完了すると 『 Welcome to the project! 』 画面が現れます。

画像15

③ソースコード管理用のリポジトリ作成

以前の記事で書いた 『 Bitbucket 』 というリモートリポジトリではなく、

せっかくなので今回は Azure のサービスである 『 Azure Repos 』 を使います。
見た目が違うだけで基本的に同じと思ってもらって問題ありません。

Azure Repos は、コードの管理に使用できるバージョン管理ツールのセットです。
公式ドキュメント:Azure Repos とは

① 『 Repos 』 をクリックし、②『先ほど作成したプロジェクト名』をクリックします。

画像16

『 New repository 』 をクリックです。

画像17

今回は 『 test-repository 』 という名前で作成しました。
ちなみに、README や .gitignore などファイルは一切作成しませんでした。
完全に空の状態でリポジトリが作成されます。

画像18

Git の使い方については、以下のマガジンの記事をぜひ参考にしてみてください。

ここで画面にはいくつかの最初の操作の指示 ( test-repository is empty. Add some code! ) というかが記載されていますが

⭐ Clone to your computer
・ Push an existing repository from command line
・ Import a repository
・ Initialize main branch with a README or gitignore

まだ記事としてはご紹介していなかった 『 Clone ( クローン ) 』 を今回使おうと思います。
本筋から外れるので詳細は割愛しますが、リモートリポジトリをローカル環境にクローン(複製)するコマンド(操作)です。

以下の画像の状態の赤矢印 ( ① ) が指す部分をクリックすると、https ではじまる URL がクリップボードにコピーされます。
この URL情報は、後ほど行う『 クローン操作 ( git cloneコマンド ) 』で必要になります。

画像19

あとは、② ( Generate Git Credential ) もクリックしてください。
すると、『 password 』情報をコピーできます。
この情報もクローン操作の際に必要になります。

なお、この password情報は、クローン操作だけでなくその後の ( push や pull といったリモートリポジトリに対する)命令時にも度々必要になります。
再発行(表示)はしてくれないようなので、必ずどこかにメモ(保存)をして後から何回も確認できるようにしてください

画像24

これらの情報を入手したら、リポジトリ(フォルダ)を作成したい場所で 『 Git Bash 』 のコンソールを立ち上げてください。

念のため、操作するローカルPC ( Windows でも Mac でも良いですが ) には、Git の環境が整っていることが前提となります。
※今回の環境としては、Windows 10 ( Git for Windows ) で行っています。

参考までに Windows に Git 環境を整えるのに役に立つ情報を載せておきます。

Git Bash に関する情報は以下の記事でも紹介しています。

Git のコマンド操作に抵抗がある方は、SourceTree ( GUI ) での操作も可能ですので以下の記事も役に立つかもしれません。

まずは、クローンしてローカルリポジトリを作成する場所(フォルダ)に移動します。

mevius@SurfaceLaptop MINGW64 ~/Documents/AzureReposRepository 
$ pwd 
/c/Users/mevius/Documents/AzureReposRepository 👈今回はここに作成(クローン)することにした

『 git clone 先ほど①でコピーしたURL 』とコマンドを打ちます。

mevius@SurfaceLaptop MINGW64 ~/Documents/AzureReposRepository
$ git clone https://mevius01@dev.azure.com/mevius01/test-project/_git/test-repository 
Cloning into 'test-repository'...

すると以下のように認証を求められるので、アカウントを選択します。

アカウントを選択する

でも、選択しただけでは以下のようなコメントがでるので

Logon failed, use ctrl+c to cancel basic credential prompt.

別途開く、『 OpenSSH 』のウィンドウにて、先ほど②でコピーしたパスワードを入力します。

画像21

すると以下のコメントが表示され完了です。
「空のリポジトリをクローンしたみたいだけど、それでイイの?」的なことですが、実際に空と知っていて行っているので全く問題ありません

warning: You appear to have cloned an empty repository.

クローンされた「 test-repository 」という名のフォルダに移動し、一応中身を確認してみます。
はい、見事に何もありません。「 .git 」という隠しフォルダが当然ありますがその他のファイルは何もありません。
想定通りです。

mevius@SurfaceLaptop MINGW64 ~/Documents/AzureReposRepository/test-repository (master) 
$ ls -lA 
total 0 
drwxr-xr-x 1 mevius 197121 0 Oct 12 21:55 .git/ 👈

一応、エクスプローラーでも見てみますが当たり前ですが同じ状態です。

画像22

リモートリポジトリの登録状況も念のため見てみます。
『 git remote -v 』 とコマンドを打つとわかります。

先ほど Azure Portal ( Azure DevOps ) で作成したリポジトリが(クローンしたので当たり前ではありますが)リモートリポジトリとして登録されているのが確認できました。

mevius@SurfaceLaptop MINGW64 ~/Documents/AzureReposRepository/test-repository (master)
$ git remote -v 
origin  https://mevius01@dev.azure.com/mevius01/test-project/_git/test-repository (fetch) 
origin  https://mevius01@dev.azure.com/mevius01/test-project/_git/test-repository (push)

ここからが大事なところです。
現在はファイルが何もないので、まずは追加して Push します。

今回は、『 index.php 』 ファイル(内容は以下参照)を作成しました。

<?php  
   echo 'Hello world!'; 
?>

ちなみに、Git Bash でもファイルを作成 ( vi / vim エディタ ) できますし、メモ帳を使ってファイル作成するという方法など色々ありますが、以前に書いた記事でもご紹介した Visual Studio Code ( VScode ) に Git の拡張機能を入れた状態で操作するのがスマートかもしれません。
見やすいし、Git の操作も含めてそこで完結するので。

ということで Push まで行い、ローカル / リモートリポジトリの master ブランチにコミットが一つだけ追加された状態になりました。

コミットが追加された

🟢 CI/CDパイプラインの構築 🟢

ここまでで、大前提環境の準備が整いましたので、ここからは準備の最後の詰め、最も大事な CI/CDパイプラインの構築を行っていきます。

Azure Pipelines というサービスでパイプラインを作成していきます。

Azure Pipelinesプロジェクトを自動的にビルドしてテストし、他のユーザーが使用できるコード プロジェクトを作成します。 ほぼすべての言語やプロジェクトの種類で機能します。 Azure Pipelines統合 (CI) と継続的デリバリー (CD) を組み合わせ、コードをテストしてビルドし、任意のターゲットに出荷します。
公式ドキュメント:Azure Pipelines とは

画像64

出典新しい Azure Pipelines ユーザー向けの主要な概念

以下の画面を表示し、『 Create Pipeline 』をクリックします。

画像26

すると、リモートリポジトリサービスを選択する画面に遷移するので、『 Azure Repos Git 』を選びます。

画像27

変更を監視する対象となるリポジトリの選択する必要があるので、先ほど作成した ( Push まで行った )『 test-repository 』を選びます。

画像28

すると、「どこでビルドやデプロイを行いますか?」と聞かれるので、『 PHP as Linux Web App on Azure 』を選びます。
最初に作成した、App Service のことです。

画像29

すると、この App Service のリソースが紐づくサブスクリプションを聞かれるので該当するものを選んでください。

画像30

あと、その App Service に付けた名前も指定します。

画像31

すると 『 azure-pipelines.yml 』 というファイルのエディタ画面に遷移します。
このファイルを編集することで、自分が行いたいパイプラインの詳細について定義していきます。

画像32

今回は割愛しますが、もっと詳しく内容や使い方を知りたい方は公式ドキュメントをご確認ください。

Azure Pipelinesエディターに基づく YAML パイプライン エディターが提供されます。このエディターを使用すると、ポータルからパイプラインを作成および編集Azure DevOpsできます。 エディターには、Intellisense のサポートや、パイプラインを編集するときにガイダンスを提供するタスク アシスタントのようなツールが提供されます。
公式ドキュメント:YAML パイプライン エディター

自動的に YAMLファイルの中身が作成されていますが、以下のように修正していきます。
大枠としては、自動的に記述された2つの 『 ステージ 』 の内容を修正し、新しく1つの 『 ステージ 』 の内容を追記します。

ステージは、パイプライン内の論理的な境界です。 これを使用すると、関心の分離 (ビルド、QA、運用など) をマークすることができます。 各ステージには、1つまたは複数のジョブが含まれます。 パイプラインで複数のステージを定義すると、既定では、1つのステージの後に複数のステージが実行されます。 ステージを実行する条件を指定できます。
公式ドキュメント:ステージ

① 『 Build 』 ステージの修正

  variables:
   phpVersion: '7.4'

と書き換え

    - script: composer install --no-interaction --prefer-dist 
     workingDirectory: $(rootFolder) 
     displayName: 'Composer install'

の部分を丸々削除しました。

そして最終的には以下のようにしました。

- stage: Build
 displayName: Build stage
 variables:
   phpVersion: '7.4'
 jobs:
 - job: BuildJob
   pool:
     vmImage: $(vmImageName)
   steps:
   - script: |
       sudo update-alternatives --set php /usr/bin/php$(phpVersion)
       sudo update-alternatives --set phar /usr/bin/phar$(phpVersion)
       sudo update-alternatives --set phpdbg /usr/bin/phpdbg$(phpVersion)
       sudo update-alternatives --set php-cgi /usr/bin/php-cgi$(phpVersion)
       sudo update-alternatives --set phar.phar /usr/bin/phar.phar$(phpVersion)
       php -version
     workingDirectory: $(rootFolder)
     displayName: 'Use PHP version $(phpVersion)'
   - task: ArchiveFiles@2
     displayName: 'Archive files'
     inputs:
       rootFolderOrFile: '$(rootFolder)'
       includeRootFolder: false
       archiveType: zip
       archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
       replaceExistingArchive: true
   - upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
     displayName: 'Upload package'
     artifact: drop

② 『 Test 』 ステージを追記

『 Build 』 ステージと 『 Deploy 』 ステージの間に、以下の記述を挿入しました。

- stage: Test  
 displayName: 'Test Stage (Deploy Stage Slot)'  
 dependsOn: Build  
 condition: succeeded()  
 jobs:  
 - deployment: DeploymentJob  
   pool:  
     vmImage: $(vmImageName)  
   environment: $(environmentName)-staging
   strategy:  
     runOnce:  
       deploy:  
         steps:  
         - task: AzureWebApp@1  
           displayName: 'Deploy Azure Web App : mevius-php'  
           inputs:  
             azureSubscription: $(azureSubscription)  
             appType: 'webAppLinux'  
             appName: 'mevius-php' 👈作成した App Service名
             deployToSlotOrASE: true  
             resourceGroupName: 'Test-CICD-rg' 👈App Serviceに紐づくリソースグループ
             slotName: 'staging' 👈ステージングスロット名
             package: '$(Pipeline.Workspace)/drop/$(Build.BuildId).zip'

③ 『 Deploy 』 ステージの修正

以下のように修正しました。

- stage: Deploy  
 displayName: 'Deploy Stage (Swap Slots)'  
 dependsOn: Test  
 condition: succeeded()  
 jobs:  
 - deployment: DeploymentJob  
   pool:  
     vmImage: $(vmImageName)  
   environment: $(environmentName)  
   strategy:  
     runOnce:  
       deploy:  
         steps:  
         - task: AzureAppServiceManage@0  
           inputs:  
             azureSubscription: $(azureSubscription)  
             Action: 'Swap Slots'  
             WebAppName: 'mevius-php' 👈作成した App Service名
             ResourceGroupName: 'Test-CICD-rg' 👈App Serviceに紐づくリソースグループ
             SourceSlot: 'staging' 👈ステージングスロット名

書き換えたら、『 Save 』します。

画像33

ちなみに、以下の画面では「直接 masterブランチにコミットするよ」となっていますが、今回これで問題ありません。
普通はやらないですけどね。

画像34

すると以下の画面に遷移します。

画像35

ここからは、先ほどの YAMLファイル内に以下のように記述している箇所があるのですが、それに関連する設定を行っていきます。

  jobs:  
 - deployment: DeploymentJob  
   pool:  
     vmImage: $(vmImageName)  
   environment: $(environmentName)-staging
  jobs:
 - deployment: DeploymentJob   
   pool:  
     vmImage: $(vmImageName)  
   environment: $(environmentName)

『 Environments 』をクリックし、その画面にでてくる運用スロット名をクリックしてください。

画像36

遷移した画面右上にある、縦に並んだ三つの点をクリックします。

画像37

ここで表示された『 Approvals and checks 』をクリックします。

画像38

遷移した画面にある『 Approvals 』をクリックします。

画像39

ここで、ステージングスロットと運用スロットをスワップする際に、その行為を承認する人(アカウント)を選択します。
まあ個人で作っている検証環境の場合、自分のアカウントになるかと思います。

画像40

すると、承認者が登録されました。

画像41

ここで再び『 Pipelines 』 の画面に戻ると、先ほどと様子が変わっています。
先ほど作成 ( Save ) したパイプラインの実行が始まっています。
始まっているパイプラインの表示部分をクリックしてもう少し詳しく状態を見てみます。

画像42

『 Stages 』に「 - 」でつながった三つの「 ○ 」が表示され、それぞれ状況が異なるようです。
先ほど同様に、パイプラインの表示部分をクリックしてもう少し詳しく状態を見てみます。

画像43

ここまでくると、三つの ○ の正体がわかりましたね。
そう、先ほど作成した YAMLファイルに記述したステージを表していたのでした。
左から『 Build, Test, Deploy 』です。
✅は完了を意味しており、この画面ショットでは Testステージでのデプロイ、つまりは App Service のステージングスロットにデプロイ完了したことを意味します。

Deployステージについては、『 Waiting 』ということで処理が止まっており、何やら注意コメントが表示されています。
そう、これが先ほど設定した Environments の承認の影響です。

『 Review 』をクリックします。

画像44

すると、承認するか否かを求められるので、もちろん承認します。

画像45

すると、Deployステージの処理も動き出し最後まで進みました。
承認がないと運用(本番)環境へはデプロイされないように設定したわけです。
実際に考えても最終確認してから、本番環境へは反映させたいですよね~てなもんです。

画像46

💡補足

このようなパイプライン処理を進める中で、リソースへのアクセス許可が必要になる場合もあります。
そうなった場合には、注意コメントがでてくるので、それに従って許可を出すことで止まっている処理を先に進めることができます。

さて、ここで『 Repos 』の先ほど作成したリポジトリを表示してみてください。
先ほどと少し様子が変わり、パイプライン定義ファイル ( .yml ) が追加されコミットも増えています。
もちろんこのファイルの中身は先ほど編集して Save した内容になっています。 

そう、このパイプラインは masterブランチにコミットが追加されると、それをトリガーにパイプラインの処理が走るようになっていたのでした。

画像47

App Service の状況も確認してみましょう。

まずは、運用スロットのURLをブラウザで開いて、内容確認してみると先ほど作成した index.php の内容が表示されました。

運用スロット

では、ステージングスロットはどうでしょうか?
デフォルトページのままになっています。
つまり index.php の内容は再現されていないことになります。

ステージングスロット

ただ、

これでイイのです!

どうゆうことか解説しますね。

Testステージまでのパイプライン処理が完了した時点で、

ステージングスロット:Hello world!が表示される状態
運用スロット:デフォルトページの状態

だったわけです。

この後、Deployステージの処理でこれらをスワップ(入れ替え)させたわけです。
つまり、これがやりたかったのです。

🟢 (本格的に)パイプラインの実行 🟢

さて、ここまでの下準備で、このパイプラインがどうゆう挙動をするかわかってもらえたと思います。

ここからが大トロの部分です!

ここでは細かく解説しませんが、リモートリポジトリが進んだ状態になり、ローカルリポジトリは遅れた状態になっているので、まず git pull を行い、ローカルリポジトリをリモートリポジトリの状態と同じにします。

画像50

そのあと、ローカル側で新しいブランチを切り、 index.php ファイルに変更を加え「 ! 」がいっぱい表示されるように修正しました。

<?php  
   echo 'Hello world!!!!!!!!!!!!!'; 
?>

そして Push しました。
これでローカルとリモートの差分はなくなりまして、新しいブランチのコミットもあるのでプルリクエストも行える状態になったのです。

画像51

画像52

ということで、プルリクを作成しその内容でパイプラインを動かしてみたいと思います。
masterブランチにマージしてコミットが作成されるので、それを検知したパイプラインは処理を開始し始めるわけです。

画像53

Azure Repos の場合はまず『 Complete 』をクリックします。

画像54

そのあと、マージ処理の内容を指定し処理を行わせます。

画像55

はい、マージされた!と同時にパイプラインが動き出します。

画像56

先ほど同様に Testステージ完了時点で処理が止まりました。

画像57

この状態で、ステージングスロットの状態を除いてみましょう。
はい、バッチリ「 ! 」がいっぱいの Hello World が表示されました。

ステージングスロットのデプロイ確認-2nd

止まっている処理を承認することで進めていきます。
この後スワップが行われるわけですね。

画像59

画像60

はい、無事完了しました。

画像61

運用スロットを覗くと、当然変更が反映されています。

運用スロット二回目完了

ステージングスロットはというと、こちらもばっちりスワップされていますね。

ステージングスロット二回目完了

はい、ということで

問題なく想定通り完了です!

🟠 今回はここまで 🔚

いかがだったでしょうか?

かなり単純なものでしたが、なんとなくのイメージは掴めたのではないでしょうか?

今回の App Service の部分が実運用している Webサーバーであり、例えば

とある Webページの見た目などを修正する必要がでてきた

なのでそれに従ってソースコードを修正しその内容を一旦影響がでない環境に再現してみた

問題がなかったのでサイトビジターに実際に見せる本番環境に反映させた

と考えるとより親近感が湧くかもしれません。

最後までお読みいただきありがとうございました 😊

▶ おススメ学習書籍(Azure関連)


この記事が参加している募集

最近の学び

もしこの記事が何かの参考になったもしくは面白かったという方は、応援していただけると大変嬉しいです😊 これからもよろしくお願いします。