インターネットにつながらないオンプレミス環境でも自動ビルド・自動テスト・自動デプロイをしたい 

昨年、インターネットに接続できない環境で Azure DevOps Server 2019 を使用して、CI/CDできるようにしたので、忘れないうちにやり方をメモします。

## 背景

現在ではクラウドの Azure DevOps を使用できれば、簡単にCI/CDを構成できます。開発者がコードを変更したら、自動的にビルドして、テストを行い、開発・動作確認用のWebサーバーなどに自動的にデプロイ。管理者に承認依頼が送信されて、承認すると、次のテスト環境や運用環境に自動でデプロイされる、という構成を簡単に作ることができます。

※CI/CD : Continuous Integration（継続的インテグレーション）/ Continuous Delivery（継続的デリバリー）

現代の開発では、このCI/CDなしにはもはや開発をすることができないと言っても過言ではありません。たとえクラウドのAzure DevOpsを使えなくても、常にCI/CDを実現したいものです。今回は、Azure DevOps Server（オンプレミス版の Azure DevOps、旧称 Team Foundation Server : TFS ）を使用してこれを実現しました。


![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/37dcbaf5-c532-cc82-f18b-b52170b7651b.png)

今回はこのフローを実現しました。ソースコードを変更すると自動的にWebサーバーに配置されます。

このフローでは最初に（1）開発者は使用する NuGet パッケージをAzure DevOps Serverの Artifacts に登録します。これによって自動ビルド時にNuGetパッケージのRestoreができるようになります。この環境ではインターネットに接続できないため、これが無ければ使用するパッケージを全てソース管理（Git）に含めなければならなくなりますが、それはやりたくないので、ソース管理とは別にパッケージ専用の保存先に保存しています。

次に（2）開発者はReposのGitに開発したアプリのソースコードを保存します。すると（3）自動的にビルドパイプラインが開始されます。（4）Azure DevOps Server はビルドの具体的なタスクの実行をビルドサーバーに依頼し、（5）ビルドサーバーがビルドを実行します。

一般的なビルドタスクでは最初に（6）ソースコードを取得します。その後（7）、ソースコードの内容から判断して、パッケージのRestoreを実行します。通常 Restoreはソースコードには含まれていないが、ソースコードから使用されているパッケージを、インターネットに接続して取得します。この環境ではインターネットに接続する代わりに今回はArtifactsから取得します。そして（8）ソースコードとパッケージを使用してビルドします。最後に（9）ビルド結果と成果物（作成されたアプリ）は Azure DevOps Serverに保存されます。

ビルドが成功すると（10）自動的にリリースパイプラインが開始されます。（11）最初のステージ、ここでは開発用のWebサイトのサーバーに、ビルドされた成果物の配置を依頼します。（12）リリースのタスクが実行されると、（13）Azure DevOps Serverに保存されている成果物がWebサーバーにコピーされ、（14）IISのWebサイトとして配置・構成されます。

この例では次のステージはありませんが、実際に使用する場合にはテスト環境やUAT(ユーザー受け入れ試験)環境のステージを経て、最終的に本番環境のステージへデプロイします。それぞれ、承認者を指定できるので、承認者が承認すると自動で次のステージへデプロイされる、というフローを構成することができます。


## 構築手順

クラウドの Azure DevOps であれば、申し込み手続き後、数秒から数分程度で、この構成を実現するためのおおよその設定が終わった状態になります。さらにデプロイ先がAzureであれば、最初にソースコードをReposに登録して、ビルドパイプラインとリリースパイプラインを作成すれば、ものの30分程度で最初のデプロイが成功すると思います。

しかし、オンプレミスの Azure DevOps Server ではもう少し追加の準備が必要です。また、インターネットに接続できない環境では、インストール作業そのものが少し難しいので、その手順も併せて確認して準備しておく必要があります。何度かインターネットに接続できる環境でダウンロードしたファイルを、このインターネットに接続できない環境にコピーして持ち込む必要があります。何らかの「ファイルを渡す仕組み」を用意しておきます。

その他、開発に使用するPCや、認証に使用する Active Directory（ドメインコントローラー）、Azure DevOps Server をインストールするサーバー、ビルド・テスト用のサーバー、デプロイ先のWebサーバーを事前に用意しておいてください。ブラウザは必要に応じて Chrome をインストールします。

以下が、必要な手順の流れです。

1. SQL Server の ISO をダウンロードしてオフラインインストール
2. Azure DevOps Server の ISOをダウンロードしてオフラインインストール
3. Visual Studio の機能をダウンロード（キャッシュ）して Buildサーバーにオフラインインストール
4. Build Agent をダウンロードしてインストール
5. NuGetコマンドの最新版をダウンロードしBuild Agentに配置
6. NuGetサーバーの代わりに、Artifactsを構成
7. Azure Artifacts Credential Provider をダウンロードしてインストール（NuGet.configの作成とビルドパイプラインの設定変更も必要）
8. ビルドパイプラインで自動ビルド・自動テストを構成
9. 配置グループの構成・Agent をダウンロードしてインストール（.NET Core ホスティング バンドルのダウンロードとインストールも必要）
10. リリースパイプラインで IIS Webサイトのデプロイを構成
11. リリースパイプラインで自動リリースを構成

この後、詳細を説明します。

## 手順 1. SQL Server の ISO をダウンロードしてオフラインインストール

Azure DevOps Server のデータは SQL Server に保存されます。先に、SQL Server をインストールします。

最初にインターネットに接続できる環境で、インストーラをダウンロードする必要があります。オフラインインストールを行うには、(Web Installer ではなく) iso ファイルをダウンロードします。サブスクリプションのページからダウンロードできる他、このサイトでダウンロ―できるWebインストーラを使ってもダウンロードできます。

https://www.microsoft.com/ja-jp/sql-server/sql-server-downloads

Webインストーラをダウンロードして起動すると、SQL Serverをインストールするメニューの他に「メディアのダウンロード」というボタンが表示されます。

![image3-downloadSqlserver.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/9e2cdfa9-729b-fee3-9175-508e829e7edb.png)

ここからISOイメージをダウンロードすることができます。

ダウンロードしたISOファイルを、Azure DevOps Server をインストールするサーバマシンにマウントしてインストーラを起動し、表示される画面に従ってインストールします。

参考：[Azure DevOps Server 2019 Install Guide](https://www.benday.com/2019/04/04/azure-devops-server-2019-install-guide/)

## 手順 2. Azure DevOps Server の ISOをダウンロードしてオフラインインストール

2019年９月現在最新の Azure DevOps Server 2019 Update 1 をインストールします。

インターネットに接続できる環境で、インストーラをダウンロードする必要があります。オフラインインストールを行うには、(Web Installer ではなく) iso ファイルをダウンロードします。サブスクリプションのページか、Visual Studio のページでダウンロードできます。

https://visualstudio.microsoft.com/ja/downloads/

Visual Studio のページからダウンロードする場合は、「全てのダウンロード」に Azure DevOps Server 2019 Update 1 があるのでそこから ISO を選んでダウンロードします。

![image4-downloadAzureDevOps.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/03b3b361-33f4-de2b-56f6-8b16aaefd357.png)

もし、より新しいバージョンが既に出ているはずなのにここに表示されない場合は、Web ページの一番下にスクロールすると表示言語を変更できるので、日本語から英語に変えてみてください。最新版も表示されるはずです。（RC はリリース候補版なので、運用に使用するバージョンではありません）

ダウンロードしたISOファイルを、Azure DevOps Server をインストールするサーバマシンにマウントしてインストーラを起動し、表示される画面に従ってインストールします。

参考：[Azure DevOps Server 2019 Install Guide](https://www.benday.com/2019/04/04/azure-devops-server-2019-install-guide/)

インストールが完了すると、ここまでで Azure DevOps Server のWeb画面にログインして、Reposのソース管理（Git）などの基本的な機能を使用できるようになっています。Azure DevOps Server のWebページをブラウザで開いて、ページが表示されることを確認してください。

![image5-openAzureDevOps.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/d2acffff-c753-32e2-0ca2-29ddf6ec0953.png)

指示に従ってチームプロジェクトを作成すると、Repos や Pipeline などの機能のアイコンが表示されるプロジェクトの画面に進むことができます。ここに今回のフローを実現するパイプラインを作成していきます。

## 手順 3. Visual Studio の機能をダウンロード（キャッシュ）して Buildサーバーにオフラインインストール

ビルドを行うサーバーに、Visual Studio をインストールします。おそらくこの手順が一番手間と時間がかかると思います。

Visual Studio 2019 のISOファイルは無く、オフラインインストールを行うには、インターネットに接続してファイルをダウンロードする作業と、そのダウンロードしたキャッシュを使用してインストールする作業を、コマンドで実行しなければなりません。サブスクリプションでもISOのダウンロードが無いので注意が必要です。

https://visualstudio.microsoft.com/ja/downloads/

コマンドを実行するために、Webインストーラをダウンロードします。Visual Studioのサイト、サブスクリプションのサイトどちらからでもダウンロードできます。

参考：[Visual Studio のオフライン インストールを作成する](https://docs.microsoft.com/ja-jp/visualstudio/install/create-an-offline-installation-of-visual-studio?view=vs-2019)

また、全ての機能をダウンロードしてキャッシュすると現在 35GB あるということで、これをインターネットに接続できない環境に持ち込む準備はなかなか難しいと思います。使用する機能を選択してダウンロードするように、コマンドを準備する必要があるかもしれません。

参考：[Visual Studio のネットワーク ベース インストールを更新する](https://docs.microsoft.com/ja-jp/visualstudio/install/update-a-network-installation-of-visual-studio?view=vs-2019)

さらに、このインストール作業は初回の１回限りではなく、開発PCの Visual Studio を更新するのに合わせて、ビルドマシンの Visual Studio も更新しなければなりません。少なくとも、開発PCと同じプロジェクト・ソースコードをビルドできるようにメンテナンスし続ける必要があります。出来れば、開発者がVisual Studio を使用する開発PCでも、ビルドマシンと同じキャッシュからインストール・更新するように構成すると、バージョンが食い違わずに良いと思います。

開発PCとビルドマシンでVisual Studio インストール用のキャッシュを共有できるように、共有フォルダなどを構成し、そこにファイルをダウンロード（キャッシュ）するようにコマンドを実行します。（あるいはインターネットに接続できる環境でコマンドを実行した後、そのファイルをインターネットに接続できない環境の共有フォルダなどに持ち込めるように構成します）

ビルドマシン（と、必要に応じて開発PC）からキャッシュを利用できるようになったら、コマンドを実行してVisual Studioをインストールします。また、ビルドに使用するSDKやVisual Studioの拡張機能、その他サードベンダー製のツールなどがある場合には、それらも合わせてインストールします。

※もし、Visual Studio のインストールより先に次の「Build Agent のインストール」を行った場合には、この Visual Studio のインストールの後にもう一度 Build Agent の構成の PowerShell コマンドを再実行してください。

参考：[Visual Studio の展開時にプロダクト キーを自動的に適用する](https://docs.microsoft.com/ja-jp/visualstudio/install/automatically-apply-product-keys-when-deploying-visual-studio?view=vs-2019)

Visual Studio のインストールが完了したら、忘れずにプロダクトキーを登録します。プロダクトキーの登録を忘れると、30日後にビルド中にライセンスが無い旨のエラーが表示されてビルドに失敗する場合があります。このエラーは、ビルドが実行されるプロセスでVisual Studioのプロダクトキーの登録が確認できない場合に発生し、経験上、同じアカウントでVisual Studioを起動してプロダクトキーを入力しても、エラーを回避できないようです。必ずコマンドを実行して、プロダクトキーを登録します。

## 手順 4. Build Agent をダウンロードしてインストール

手順2の Azure DevOps Server をインストールが完了すると、クラウドのAzure DevOpsを使用するときと同じようにWeb画面が表示され、ほぼ同じように使えるように見えます。しかしこのままではクラウドと違って、Build Agent が構成されていないので、パイプラインを使用して自動ビルド・自動テストを行うことができません。オンプレミスでは自分でデフォルトの Build Agent を登録する必要があります。

参考：[Azure DevOps Server 2019 Install Guide](https://www.benday.com/2019/04/04/azure-devops-server-2019-install-guide/)

Build Agent は、ビルドマシンにインストールして、Azure DevOps Serverと接続し、Azure DevOps Server の Pipeline で開始したビルドとテストのタスクを、実際に実行するためのプログラムです。Azure DevOps Server のインストールが完了した後、次に、この Build Agent をビルドサーバマシンにインストールします。（お試しで環境を作ってみる場合には、Azure DevOpsサーバーと同じマシンにもインストールできます）

Build Agent をダウンロードできるURLは、既にインストールした Azure DevOps Server の Webサイトから取得することができます。Azure DevOps Server のWebサイトを開いてURLを確認し、インターネットに接続出来る環境で Build Agent をダウンロードします。ダウンロードしたモジュールをビルドマシンにコピーして、Build Agent をインストールします。

![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/556f8d3e-cb3e-3983-1591-9e4a24b80491.png)

Azure DevOps Server のサイトをブラウザで開き、チームプロジェクトの「プロジェクト設定」の中の「エージェントプール」の設定画面を開きます。ここで新しいエージェントプールを追加できます。エージェントプールは、複数のビルドエージェント（ビルドマシン）を束ねていて、複数ビルドマシンが登録されているときには、空いているビルドマシンにビルドを依頼してくれます。今回はDefaultエージェントプール１つを構成します。

エージェントプール画面の「新しいエージェント」をクリックすると、必要なモジュールがダウンロードとインストールの手順が表示されます。ただしインターネットに接続することができない環境では、この「ダウンロード」ボタンを押してもダウンロードすることができません。横のアイコンをクリックしてダウンロードするためのURLをコピーします。URLは Azure DevOps Server のバージョンによって異なります、必ずバージョンの一致するURLを確認してください。

インターネットに接続するできる環境でこのURLを開いて、Build Agent のモジュールをダウンロードします。

ダウンロードしたモジュールを（何らかの手段で）ビルドマシンに配置したら、インストールを行います。同じAzure DevOps Serverの画面で、ダウンロードしたモジュールを使用してインストール（エージェントの作成と構成）を行う PowerShell コマンドもコピーできます。

ビルドマシンにログオンして、コピーしたPowerShell コマンドを実行してエージェントをインストールします。エージェントの作成のコマンドは、ダウンロードしたファイルのパスが指定されているので、必要に応じてコマンドのファイルパスを変更して実行します。

![image6-buildagent.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/b6e022b8-e277-fd37-015c-e0b01e4eb7b8.png)

エージェントの構成のコマンドは、対話式で必要な内容を入力します。Azure DevOps ServerのURLとビルドエージェントを実行するユーザー（通常のドメインユーザー）の入力が必要になるのであらかじめ準備しておきます。その他は、サービスとして起動する に Y（はい）と応える以外は、Enterキーでデフォルト値を指定して構いません。それぞれ必要に応じて変更します。

もし、Azure DevOps Server のWebサイトが自己署名証明書の SSL（URLが https から始まる）になっている場合は、証明書をエクスポートしておいて、そのファイルを指定してエージェントの構成を実行する必要があります。

参考：[Run the agent with a self-signed certificate](https://docs.microsoft.com/en-us/azure/devops/pipelines/agents/certificate?view=azure-devops-2019)


証明書は、IISマネージャで Azure DevOps Server のサイトの「バインドの編集」で https をクリックして「編集」を押すと、「SSL証明書」で確認できます。「TFS Self-Signed SSL」から始まる名前の証明書が設定されている場合は、自己署名証明書です。隣の「表示」ボタンを押して証明書の画面を表示し、「詳細」タブから「ファイルにコピー」でエクスポートすることができます。今回は、秘密キーのエクスポートをしない、Base 64 encoded X.509 (.CER) でエクスポートしました。

```
.\config.cmd --sslcacert FileName.cer
```

エージェントの構成のコマンドの後ろにオプションを追加して起動すると、証明書を指定することができます。

※証明書の指定に失敗している場合には、後の手順で、ビルドパイプラインのビルドの Checkout でGitからのファイルの取得に失敗します。

エージェントの構成に成功すると、Azure DevOps Serverの画面にエージェントが表示されます。

![image7-agentlist.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/000da7fa-396c-47eb-63f5-75a3b8c84559.png)

エージェントプールの設定の「エージェント」の画面でオンラインになっていることを確認してください。

もしBuild Agent  の構成後に、ビルドマシンのVisual Studioの構成を変更した場合には、Build Agent の構成もやり直してください。Build Agent は、自身のサーバーでどのビルド機能が使えるか？Visual Studioがインストールされているか？を確認して、その内容は記録されているので、Build Agent の構成の PowerShell コマンドを実行した瞬間にインストールされていた機能が、使用できる機能として Azure DevOp Server に表示されます。他のバージョンの Visual Studio をインストールした場合などに、構成をやり直します。

※構成のやり直しが必要かどうか？を画面で確認することができません。後の手順で、ビルドパイプラインのビルドに失敗したときに、ビルドに必要な機能を持ったエージェントが見つからない旨のメッセージが表示されていたら、構成のやり直しを行います。

ここまでの手順で、Pipelines を使って（nugetパッケージを使っていない）ごくシンプルなプログラムはビルドできるようになりました。

動作を確認するには、実際にビルドパイプラインを作成してビルドを実行します。Visual Studio の使用できる開発PCで、Azure DevOps Server のWebページを表示し、Repos のページに移動します。Gitの新しいリポジトリを作成し、画面の指示に従って Visual Studio 用の .gitignoreファイルを作成します。その後、リポジトリのページの「複製」ボタンを押すと表示される画面の、IDEから「Visual Studio 」を選択できます。選択すると Visual Studio が起動し、リポジトリのクローンが作成され、すぐにソースコードを登録できる状態になります。Visual Studio の新規作成から ASP.net Core (C#) のテンプレートを選択して、ごく簡単な（Hello Worldレベルの）サンプルを作成し、デバッグ実行してWebページが開くことを確認します。チームエクスプローラの「変更」と「同期」を使って、作成したサンプルを Azure DevOps Serverに保存して、Reposの画面でソースコードが実際に保存されていることを確認します。

![image11-createbuild.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/72cc42d1-2597-e8fa-273b-a6c63b495767.png)

次に、Pipelineの「ビルド」を開き、「新規」から「新しいパイプライン」を選択し、「従来のエディターを使用する」を押します。

![image12-selectreps.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/29f91980-c178-1872-37f4-7352ecef4ac5.png)

保存したサンプルのあるリポジトリを選択して「続行」を押して、テンプレートの選択へ進みます。

![image13-build-core.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/b6a02a26-6e96-e0a0-a1f7-826134981d2a.png)

「Core」と入力して ASP.net Core のテンプレートを探して「適用」を押すと、ASP.net Core のプロジェクトをビルドするためのタスクが自動的に設定されたビルドパイプラインが作成されます。まだ保存されていないので注意が必要です。赤文字でエラーになっている「エージェントプール」で、この手順で作成したエージェントプールを選択することができることを確認します。

![image14-selectagent.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/12f033e4-b997-b958-78c3-ec357fe35d2f.png)

エージェントを選択出来たら「保存してキューに登録」を押して、ビルドパイプラインを実行します。ビルドエージェントが正常に動作していれば、キューはビルドエージェントで実行されて、実行中のログや実行結果を画面で確認することができます。

![image15-result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/0bc1effc-5e92-f2cb-76c6-8c686330c28e.png)

ビルドが成功すれば、エージェントの構成は成功です。

※この確認手順では、テストプロジェクトを作成していないため、Test タスクは 「成功 1件の警告」となります。クリックして警告を確認すると「指定したパターンと一致するプロジェクト ファイルが見つかりませんでした。」と出力されていることが確認できます。

## 手順 5. NuGetコマンドの最新版をダウンロードしBuild Agentに配置


ビルドサーバーで実行されるビルドタスクには、ソースコードが使用しているパッケージを扱うための NuGet コマンドを実行するタスクがあります。そこで使用されるNuGetのバージョンが古いので、新しいバージョンをインストールします。

![image8-nugettoolinstallertask.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/7bf8650d-fb53-eb0d-225b-4282aec1518e.png)

NuGet Tool インストーラー タスクは NuGet コマンドを使用します。オプションで、インターネットに接続できる環境では最新版のNuGetを自動的にダウンロードして使用することができます。しかし、インターネットに接続できない環境ではこの機能が使用できないため、手動でダウンロードしてファイルを配置します。※ Nuget Tool インストーラ―タスクを使用しない場合はこの手順をスキップできます。

https://www.nuget.org/downloads


配置先は、（正式な手順がみつけられなくて）既にビルドマシンにインストールされているファイルを参考にしました。

```
C:\agent\_work\_tool\NuGet\5.4.0\x64\nuget.exe
C:\agent\_work\_tool\NuGet\5.4.0\x64.complete
```

バージョン番号を途中に含む、上記のルールのパスにダウンロードした nuget.exe を配置します。また、x64.complete という０KBのファイルもエクスプローラのテキストファイルの新規作成などで作成しておきます。おそらく、自動でダウンロードした場合の、ダウンロードの完了確認に使っているファイルなのか、このファイルが無いと nuget.exe は使用されません。

この手順で NuGet Tool インストーラー タスクから新しいバージョンの NuGetコマンドを使用できるようになりました。

動作を確認するには、実際に NuGet Tool インストーラ―タスクを使用するビルドパイプラインを作成して実行します。Visual Studio を使って、ASP.net (.net Framework) のごく簡単な（Hello World レベルの）サンプルを作成し、Repos の Git に新しいリポジトリを作成して保存します。Pipelineの「ビルド」で「新しいパイプライン」の画面から「従来のエディターを使用する」を選択し、保存したサンプルのあるリポジトリを選択します。

![image9-build-aspnet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/eaa48306-9ccc-5598-4ffd-24939a068262.png)

作成されたパイプラインのエージェントプールを選択し、タスクの一覧から「Use NuGet 4.4.1」タスクを開くと「インストールする NuGet.ext のバージョン」が 4.4.1 になっています。

![image10-usenuget.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/00150273-a92c-6b44-ef95-566c1bbfdc0b.png)

これをダウンロードしたバージョン（例えば 5.4.0 ）に変更します。タスクの名前も使用するバージョンに合わせたもの（例えば Use NuGet 5.4.0）に変更するとよいでしょう。「保存してキューに登録」を実行して、ビルドが成功することを確認します。

※インターネットに接続できる環境では、この画面の「一致する最新バージョンを常にダウンロードする」を選択すると、任意のバージョンを自動的にダウンロードして使用してくれます。


## 手順 6. NuGetサーバーの代わりに、Artifactsを構成

インターネットに接続できる環境では、nuget.org からパッケージをダウンロードして使用することができますが、インターネットに接続できない環境ではこれができません。Azure DevOps にはプロジェクトのメンバーだけが使用できる NuGet フィードを用意することができる Artifacts という機能があるので、ここに必要なパッケージを登録しておけば、プロジェクトのビルドに必要なパッケージを開発者やビルドサーバーが入手することができるようになります。

ただし、事前にインターネットに接続できる環境で、必要なパッケージを全て nuget.org から手動でダウンロードしておいて、この環境に持ち込んだ後、Artifacts のフィードに登録しておく必要があります。

※Artifacts の本来の使い方としては、nuget.org に公開することはできないが、プロジェクト内では共有したい独自の NuGet パッケージを作成した場合に、これを共有するためのフィードとして使用できます。Visual Studio 2019 では、プロジェクトの設定を変えるだけで、簡単にNuGetパッケージを作成することができます。そのプロジェクトをReposに登録し、
ビルドパイプラインでNuGetパッケージをビルドした後にArtifactsにアップするように構成すれば、Azure DevOps を使用する全ての開発者が、これを入手することができます。

事前準備としてアクセスキートークンを作成します。これは nuget.exe から Artifacts に接続するときに使用されるパスワードの代わりになる文字列です。Azure DevOps Server のWebページの右上、ユーザーのアイコンをクリックして「セキュリティ」を押します。ユーザー設定の「個人用アクセス トークン」の画面が表示されるので、「新しいトークン」を押して、新しいアクセストークンを作成します。この画面で作成時にしかコピーできないので、作成したらすぐにコピーして一旦メモ帳などでファイルに保存しておきます。名前や期間は任意で、スコープはフルアクセスにするか、カスタム定義で「全てのスコープを表示する」から「パッケージ」の「読み取り、および書き込み、管理」を選択します。

次にAzure DevOps Server のWebページで、Artifacts を開き「新しいフィード」を押して名前を入力してフィードを作成します。

フィードを作成したら右上の歯車から「フィードの設定」を開き、その中の「アップストリーム ソース」を表示します。

![image17-deleteUpStream.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/7eef7874-a4d7-51cb-a1f7-f163ced3ed33.png)

アップストリームソースは、開発者やビルドサーバーが NuGet パッケージをArtifactsからダウンロードするときに、代わりに nuget.org にあればそこからもダウンロードできるようにできる仕組みです。ここの nuget.org パブリックソース を選択して「削除」しておきます。これで開発者やビルドサーバーは、Artifacts だけに接続し、nuget.org へは接続しません。このアップストリームの削除を先にしておかないと、この手順でこれから行う Artifacts へのパッケージの登録でも、nuget.org へ接続してしまい（しかしインターネットに接続できないので）エラーとなってしまいます。（しかもエラーメッセージが文字化けしていて読めないので何が起きているのか、非常にわかりにくいです）Artifacts はアップストリームに登録されているパブリックソースと同じ名前・バージョンのパッケージは登録できないようになっていて、同じ名前・バージョンのパッケージが重複されて登録されて（しかし内容が違うなどで）問題が起きることが無い様な仕組みになっています。アップストリーム ソースの nuget.org を削除することで、Artifacts を nuget.org の代わりに使用できるようにします。

アップストリーム ソースを削除したら、Artifacts のフィードの画面に戻って「フィードに接続する」を押すと、「NuGet.exe を使ってパッケージをプッシュする」という部分にこのフィードを使うためのコマンドが表示されているのでこれをコピーします。

![image16-connectnugetfeed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/eb5ad793-8c5e-d998-3485-a54fbf2d8caa.png)

nuget.exe のあるフォルダでコマンドプロンプトを開いて「このフィードを追加する」のコマンドを実行すると、以降の nuget.exe のコマンドでこのフィードが使用できるようになります。

その後同じく nuget.exe のあるフォルダで、ダウンロードしておいた全てのパッケージをArtifactsに登録するコマンドを実行します。「パッケージをプッシュする」コマンドの、-ApiKey の後ろの AzureDevOps と書いてある部分を、コピーしておいたアクセスキートークンに書き換えて実行します。ファイル名を *.nupkg とワイルドカードにしておくと、複数のパッケージを一度にフィードに登録できます。

```
nuget.exe push -Source "CopiedNuGet" -ApiKey XXXXXXXXXXXXXXXXXX *.nupkg
```

もしアップストリーム ソースの削除が出来ていないとここでエラーになります。

※インターネットに接続できる環境で、アップストリーム ソースに nuget.org が入ったまま、nuget.org から入手したパッケージを登録しようとしても Conflict エラーになります。

![image18-feed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/9f917fed-9bf0-038c-eb23-e614493f175f.png)

登録に成功すると、Artifacts のフィードの画面にパッケージが表示されます。使用したいパッケージが全て登録されていることを確認してArtifactsの準備が完了です。

Visual Studio で Azure DevOps Server のチームプロジェクトに接続している場合、パッケージの管理に Artifacts が表示されて、登録しておいたパッケージを使用することができます。（設定不要で自動的に表示されるはずですが、もしVisual Studio の設定が上手くできていない場合は、「フィードに接続する」画面表示されていたURLをコピーして手動で設定することができます）

またこの段階で nuget.exe を使用するビルドパイプラインのタスクは Artifacts からの Restore が可能です。手順 5 で作成した ASP.net (.net Framework) 用の NuGet Restore タスクは nuget.exe を使用しています。Visual Studio でサンプルのプロジェクトに変更を加えて、Artifacts の NuGetパッケージを使用するようにして、Repos へ同期します。

![image19-nugetRestore.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/6c6faa2d-16af-839c-87c5-2b34f7059b53.png)

Pipeline のサンプルのビルドパイプラインを「編集」し、「NuGet restore」タスクの設定を変更します。「この Azure Artifacts/TFS フィードからのパッケージを使用する」で、今回作成したフィードを選択し、すぐ下の「NuGet.org からのパッケージを使用する」のチェックを外します。「保存してキューに登録」を実行して、ビルドが成功することを確認します。

※もし認証エラーで NuGet restore に成功しない場合は次の手順 7 を先に実施してください。


## 手順 7.  Azure Artifacts Credential Provider をダウンロードしてインストール（NuGet.configの作成とビルドパイプラインの設定変更も必要）

手順 6 の段階で、nuget.exe から Artifacts を使用した restore は成功するようになっていますが、dotnet.exe を使用する場合は認証がうまくいかない場合がある状態です。nuget.exe を使用する「NuGet restore」タスクと同様の設定で、dotnet.exe を使用する .NET Core の「Restore」タスクも実行できる場合もあるようなのですが、うまくいかない場合もあるようです。

![image20-dotnetRestore.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/276016f8-374c-d0df-20fc-db1171e0b516.png)

タスクの編集画面では「この Azure Artifacts フィードからのパッケージを使用する」でフィードを選択し、「NuGet.org からのパッケージを使用する」のチェックを外して、同様の設定ができるように見えます。実際私が試したときも、これで Restore に成功する場合がありました。しかし、別の環境では、この方法では Restore 出来ない環境もあり、条件がよくわかっていません。

これを解決するためには、ビルドサーバーに Azure Artifacts Credential Provider をインストールします。

参考：[Use dotnet with Azure Artifacts feeds - On build machines and in non-interactive scenarios](https://docs.microsoft.com/ja-jp/azure/devops/artifacts/nuget/dotnet-exe?view=azure-devops#on-build-machines-and-in-non-interactive-scenarios)

Azure Artifacts Credential Provider をビルドサーバーにインストールし、それを使用する設定をビルドパイプラインの変数に登録すると、ビルドパイプラインで dotnet.exe を使用するタスクが restore を実行できるようになります。

参考：[Azure Artifacts Credential Provider - Setup](https://github.com/Microsoft/artifacts-credprovider#setup)

https://github.com/Microsoft/artifacts-credprovider/releases

インターネットに接続できる環境で、Azure Artifacts Credential Provider の zip ファイルをGitHubからダウンロードしておきます。これをビルドサーバーに持ち込めるようにします。ビルドサーバーにエージェントを実行しているユーザーでログインし、ZIPファイルを展開して、netcore フォルダをそのユーザーの .nuget\plugins フォルダに配置します。

```
C:\Users\ユーザー名\.nuget\plugins
```

これでビルドサーバーに Azure Artifacts Credential Provider をインストールできました。ビルドパイプラインの設定を変更して、Azure Artifacts Credential Provider を使用して認証できるようにします。この設定には 手順 6 と同じように、ユーザーのアクセスキートークンが必要です。ビルドパイプラインを作成（または複製）するたびに、その作成（または複製）したユーザーのアクセスキートークンを使用して、設定します（複製した場合は設定を変更します）。

手順 4 で作成したサンプルのビルドパイプラインを使用して、設定の変更を試してみます。もしビルドパイプラインを作成したユーザーで作業できない場合は、パイプラインを複製して、そのままそのユーザーで設定を変更します。

また、Visual Studio でサンプルのプロジェクトを開いて、Artifacts のパッケージを使用するするようにプロジェクトを更新し、Reposへ同期しておきます。

事前準備としてアクセスキートークンを作成します。手順 6 でフルアクセスを指定した場合は同じキーを使用することができます。そうでない場合は（おそらく）スコープを「コード」の「読み取り」にしてアクセスキートークンを新たに作成します。（ドキュメントに記載がなかったので、今回はフルアクセスで試しました。）作成したアクセスキートークンをコピーしてメモ帳などで保存しておきます。

[Azure Artifacts Credential Provider - Environment Variables](https://github.com/Microsoft/artifacts-credprovider/blob/master/README.md#environment-variables)

次にAzure Artifacts Credential Provider の Environment Variables のページにあるサンプルの設定値の名前と値をコピーします。

```
VSS_NUGET_EXTERNAL_FEED_ENDPOINTS

{"endpointCredentials": [{"endpoint":"http://example.index.json", "username":"optional", "password":"accesstoken"}]}
```

この endpoint のURLを http://example.index.json から、今回作成した Artifacts フィードのURLに変更します。フィードのURLは、「フィードに接続する」の画面からコピー出来ます。また、この password の値を accesstoken から、コピーしておいたアクセスキートークンに変更します。この設定値をビルドパイプラインで使用します。username は変更しません。


その次に、ビルドするソースコードが保存されている Repos のリポジトリに、nuget.config ファイルを作成して追加します。

[Package: NuGet Authenticate - Examples - nuget.config](https://docs.microsoft.com/en-us/azure/devops/pipelines/tasks/package/nuget-authenticate?view=azure-devops#nugetconfig-1)

Microsoftのページから nuget.config ファイルのサンプルをコピーして、URLをArtifactsフィードの内容に置き換えます。

```
<configuration>
  <packageSources>
    <add key="CopiedNuGet" value="http://example.index.json" />
  </packageSources>
</configuration>
```

nuget.config という名前でテキストファイルを保存したら、リポジトリに保存します。（Azure DevOps Server の Repos のWebページから直接ファイルを作成することができます。）

最後に、.NET Core 「Restore」 タスクを編集します。

![image21-dotnetRestoreInteractive.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/714e2a5a-3da9-cfcc-41eb-26d5aeec2615.png)

タスクの「コマンド」を restore から custom へ変更します。追加で表示される項目の「カスタム コマンド」に restore を、「引数」に --interactive を指定します。

また、タスクの「変数」を開いて、パイプライン変数「追加」を押して、変数を追加します。

![image22-Variables.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/6cabc060-98c2-5653-2b02-5f64c80aa3bb.png)

Azure Artifacts Credential Provider の Environment Variables のページからコピーして作成しておいた名前と設定値を指定します。

設定ができたら「保存してキューに登録」を押してビルドを実行して、サンプルの Restore コマンドが成功することを確認します。


## 手順 8. ビルドパイプラインで自動ビルド・自動テストを構成

ここまでの手順で 自動ビルド・自動テスト を構成できる準備が整っています。手順 7 で使用したサンプルのプロジェクト・ソースコードと、ビルドパイプラインを使用して、構成を確認していきます。

ここまでの手順で確認した通り、ビルドパイプラインの実行結果を確認すると、「Build 成功」と表示されていて、ビルドサーバーでのビルドに成功していることがわかります。そのため、今回のフローを実現するには、開発者がソースコードの変更を Repos に同期するとそれをトリガ―として、このビルドパイプラインが自動的に実行されるように構成すればOKです。

![image24-trigger.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/b7c331e8-e6e9-e903-8fb6-7751f7a66790.png)

これはとても簡単で、ビルドパイプラインの「トリガ―」で「継続的インテグレーションを有効にする」をチェックするだけです。必要に応じてブランチやパスのフィルターを指定できます。チェックした後、設定を「保存」し、キューに登録するかわりに、ソースコードを変更して Repos に同期します。自動的にビルドパイプラインが実行されることが確認できます。

また、「Test 成功 1件の警告」と結果に表示されていることから、ビルド直後にテストを実行しようとしたが、まだテストプログラムが無いのでテストが実施されなかったことがわかります。

参考：[単体テストの基本](https://docs.microsoft.com/ja-jp/visualstudio/test/unit-test-basics?view=vs-2019)

Visual Studio の機能を使用して、サンプルプロジェクトに単体テストプロジェクトを追加すると、ビルドパイプラインはそのテストプロジェクトを命名規則で見つけて自動的にテストを実行することができます。

![image23-tests.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/3d218a8a-a7ce-8f9d-7533-c0ac611e8e1c.png)

既定では単体テストプロジェクトの名前を ○○Tests という名前にすれば、自動的にテストされます。変更したい場合はビルドパイプラインの「テストするプロジェクト」の項目を変更すると、任意の名前のテストプロジェクトを開始することが出来ます。

これで自動ビルド・自動テストの構成は完了です。

## 9. 配置グループの構成・Agent をダウンロードしてインストール（.NET Core ホスティング バンドルのダウンロードとインストールも必要）

ここからはWebサーバーへのデプロイ、自動リリースのための準備を進めていきます。

ビルドパイプラインでビルドするためにはビルドエージェントをインストールしたビルドサーバーが必要でした。ビルドサーバーはエージェントプールに登録されていて、ビルドパイプラインがキューに入れられるときに、空いているエージェントが選択されてビルドが実行されるという仕組みになっています。今回の例ではビルドサーバーが1つしかないので効果が実感できないと思いますが、複数のビルドサーバーがあれば、キューに入ったビルドは、複数のビルドサーバーで同時に処理されていきます。

デプロイも少しこれと似ています。リリースパイプラインはエージェントをインストールしたサーバーに、ビルド済みの成果物をデプロイすることができます。リリース用にエージェントをインストールするときに、「配置グループ」に登録します。リリースパイプラインは、指定された配置グループに対してデプロイを実行します。配置グループには複数のサーバーを登録しておくことができます。またサーバーにタグを指定できるので、デプロイ時に例えば「検証用の 配置グループ（サーバー群）の中の web のタグがあるサーバーにでデプロイする」というような指定もできます。今回は1つの配置グループ、1つのサーバーしか使用しませんが、実際の自動リリースを構築するときには、配置グループをどのように構成するか、検討して準備をします。

ということで、リリースパイプラインを使用するために、まず最初に「配置グループ」を作成し、リリースエージェントをデプロイ先のサーバーにインストールして配置グループにサーバーを登録します。

Azure DevOps のWeb画面で Pipelines の「配置グループ」を表示して、新しい配置グループを作成します。ここは名前を指定するだけで作成できます。

![image25-deploygroup.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/79c60a49-9720-b7c9-6509-c2f3a24f1b5f.png)

作成した配置グループの画面で、「登録スクリプト（PowerShell）」をコピーすることができます。これをコピーしてテキストファイルに一旦保存しておきます。

実はこのスクリプトには、Agent のZIPファイルをインターネットからダウンロードする処理が記載されています。インターネットに接続できない環境で、このスクリプトを実行すると、この部分でエラーになります。そこでこのファイルを3つに分割します。

1つ目はダウンロードより前の処理。2つ目はダウンロードする処理。3つ目はファイルをダウンロードした後の処理です。

```
$WebClient=New-Object Net.WebClient; $Uri='https://vstsagentpackage.azureedge.net/agent/2.153.1/vsts-agent-win-x64-2.153.1.zip';if($DefaultProxy -and (-not $DefaultProxy.IsBypassed($Uri))){$WebClient.Proxy= New-Object Net.WebProxy($DefaultProxy.GetProxy($Uri).OriginalString, $True);}; $WebClient.DownloadFile($Uri, $agentZip);
```
これが2つ目のファイルをダウンロードする処理の部分です。この中から URL をコピーして、インターネット接続できる環境で、ZIPファイルをダウンロードします。（※ビルドエージェントと同じファイルのように思いますが、念のためURLを確認してください）また、この処理より前の部分と、この処理より後ろの部分をそれぞれコピーして、テキストファイルとして保存しておきます。

```
“Administrator”
```

さらに1つ目のスクリプトには ダブルコーテーション の文字がこのような文字になっている部分がありますが、これは日本語環境ではエラーになって実行できないようなので、通常の " に変更しておきます。

ダウンロードしたZIPファイルと、完成した２つのスクリプトのテキストファイルを、デプロイ先のサーバーへ持ち込みます。

※今回は ASP.net Core の Web プロジェクトをデプロイするので、サーバーの IISの機能 を有効化しておきます。また、インターネット接続ができる環境で、ASP.net Core のランタイム（.NET Core ホスティング バンドル）をダウンロードしておいて、事前に サーバーへインストールしておくことも必要です。

参考：[.NET Core ホスティング バンドルのインストール](https://docs.microsoft.com/ja-JP/aspnet/core/host-and-deploy/iis/index?view=aspnetcore-2.2#install-the-net-core-hosting-bundle)

サーバーへログインしたら、管理者としてPowerShellを実行します。最初に1つ目のスクリプトを実行します。エージェントをインストールする先のフォルダが作成され（C:\azagent）、処理が終了するので、スクリプトでダウンロードされるはずだったファイルをそのフォルダにコピーします。ファイル名を agent.zip に変更したら、後半のスクリプトを実行します。

![image26-deployagent.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/c892fc01-bb6d-3f5e-4cc6-8824dd0b3cbc.png)

スクリプトの後半を実行すると、対話的にタグの指定やユーザーの指定ができますが、接続先の Azure DevOps Server やチームプロジェクト、配置グループの情報は既にスクリプトに埋め込まれているので、必要が無ければ既定値のまま（Enter キーを押して）進めて構いません。

登録が完了すると、Azure DevOps の Web 画面で、配置グループの「ターゲット」に登録したサーバーがオンラインで表示されていることを確認できます。

## 手順 10. リリースパイプラインで IIS Webサイトのデプロイを構成

Azure DevOps Pipelines の「リリース」で、「新しいリリースパイプライン」を作成します。

![image27-releasePipeline.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/569f6011-addb-ad7d-a432-1e30241600d8.png)

テンプレートの選択で IIS を検索すると、いくつかのテンプレートが表示されます。今回は「IIS Web サイトの配置」を作成します。

リリースパイプラインがテンプレートから作られたら、最低限、設定しなければならないのは２つ。1つは「成果物」、もう１つはジョブの配置先の「配置グループ」です。

![image28-releasePipelineEdit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/1e852f9d-d95a-8012-b90a-81a14d1fd7b4.png)

成果物とは、ビルドパイプラインの結果に保存されている、ビルド済みの Web アプリケーション のファイルです。ビルドパイプラインのビルドが成功し、ビルドしたファイルを結果に保存で来た時には、ビルド結果の右上に「成果物」というボタンが表示されて、それをクリックすることでダウンロードしたり内容を確認することができます。手順 7 で使用した ASP.net Core のビルドパイプラインでは、Publish Artifacts タスクが成果物を結果に保存しています。成果物が保存されていないときはこのタスクの結果を確認してみましょう。

![image29-selectArtifacts.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/9b64c9f2-3842-e721-7978-004f9aa1ff6b.png)

ビルドパイプラインのビルドが成功している状態で、リリースパイプラインの「成果物の追加」を押すと、そこで表示される画面で、その成果物を選択することができます。「ソース（ビルドパイプライン）」で使用したいビルドパイプラインを選ぶと、自動的に「既定のバージョン」が「最新」になります。これは最後にビルドに成功した成果物を使用するという意味です。オプションによって、リリース時に手動で選択する等を選べますが、ここでは自動リリースを実現したいので、「最新」のままとします。最後に「追加」を押して、成果物の追加を完了します。

次に、ステージの下に表示されている赤丸の ! マーク に注目します。ステージは、いわゆる「開発環境」や「テスト環境」、「本番運用環境」など、リリースの段階を指定できるグループです。今回は1つのステージ１しかありません。後で必要に応じて名前を変更したり、ステージを足すことができます。そのステージ１のジョブがまだ適切に設定完了していないことが赤丸の !マーク で示されています。これをクリックすると、ジョブで実行されるタスクの設定画面に移ります。

![image30-selectDeployGroup.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/477c45a0-9115-d9e8-45e9-a4c439fb153c.png)

タスクの画面を開くと、まだ設定が完了していない部分が赤文字メッセージで示されます。ここでは「配置グループ」を選択します。必要に応じてタグは、並列で複数に配置するかどうかなどが設定できます。

配置先のサーバーに IIS の機能が有効化されていて、Default Web Site が既に作成されていれば、このままの設定で IIS に Web アプリケーションをデプロイすることができます。もし、別のWebサイトや仮想アプリケーションを作成している場合には、配置プロセスの「Webサイト名」や、「IIS Web App Deploy」タスクの「仮想アプリケーション」の項目を適切に変更します。

設定が完了したら「保存」を押して、リリースパイプラインの作成は完了です。

作成したリリースパイプラインを実行するには、（日本語がちょっとわかりにくいのですが）リリースパイプラインの「リリス」ボタンから「リリースの作成」を選択します。どのビルド結果の成果物が使用されるか？画面に表示されるので、確認して「作成」を押してリリースパイプラインの実行開始です。

![image31-releaseResult.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/1a997a66-54c6-7652-1c0e-50a452e4fae7.png)

リリースの結果を確認して、正常にデプロイした Web サイトが表示されことを確認します。


## 手順 11. リリースパイプラインで自動リリースを構成

ここまでの手順で 自動ビルド・自動テスト・自動リリース を構成できる準備が整っています。（ビルドパイプラインの時と同様に）手順 10 で作成したリリースパイプラインのトリガを指定するだけで、ビルドパイプラインの新しいビルド結果が保存されるたびに、自動的にリリースが作成されるように構成できます。

![image32-releaseTriger.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474869/07593ed9-584f-560e-8d39-9eb35d45fcfc.png)

リリースパイプラインの成果物にある イナズマ のようなアイコンを押すと、「継続的配置トリガ―」を指定できます。これを有効にして、「保存」します。

この設定の後でビルドパイプラインのビルドを実行すると、自動的にリリースも実行されることを確認出来ます。

これで、開発者がソースコードを変更すると自動的にビルド・テスト・リリースが実行される構成ができました。リリースは開発環境やテスト環境に自動にリリースされることを想定しています。実際の運用では、ステージを追加して、そのステージへのリリースに承認者を指定します。最初のステージまでは開発者がコードを変更するたびに自動でリリースされ、それ以降のステージへは、承認者の承認後にリリースされるようにします。

また、各ステージで設定が同じままでは動作に問題が起こる場合があります。重要な設定をデプロイする成果物（とその元となるソースコード）に含めないことは重要です。

参考：[ASP.NET Core での開発におけるアプリシークレットの安全な保存](https://docs.microsoft.com/ja-jp/aspnet/core/security/app-secrets?view=aspnetcore-2.2&tabs=windows)

それぞれソースコードや、その成果物のデプロイとは別に管理して、各ステージの環境にあらかじめ設定しておくように検討します。


## まとめ

Azure DevOps のクラウド版を使用すると、ものの 30分程度で準備できることに、インターネット接続ができないオンプレミス環境で、Azure DevOps Server を使用すると、ものすごい時間がかかってしまいます。それも、たった1回の初回だけではなく、開発のたび、あるいは Azure DevOps Server や Visual Studio の更新のたびに。

中でも最も時間がかかるのは Visual Studio のインストール（と今後の更新）と、nuget.org へ接続できない事への対応でしょう。

また、実はインターネットに接続できない Azure DevOps Serverでは、Marketplace に接続できず、また Azure DevOps Server の拡張機能をインストールして使用することもできません。（オンプレミス環境の Azure DevOps Serverでも、インターネットに接続できれば、拡張機能をインストールして使用することができます）これはかなり大きな制限で、画面に様々な便利な機能を追加する拡張機能はもちろん、ビルドパイプラインで使用するタスクの種類を追加することもできません。例えばタスクを Marketplace から追加すれば数分で設定できるタスクが、代わりに PowerShell や自作のコマンドで対応しなければならないとすると、それもかなりのコストになってしまいます。

参考：[ファイアウォールまたはプロキシ サーバーの内側に Visual Studio および Azure Services をインストールして使用する](https://docs.microsoft.com/ja-jp/visualstudio/install/install-and-use-visual-studio-behind-a-firewall-or-proxy-server?view=vs-2019)

もし出来ることなら、このページに記載されているURLへ接続可能なように、調整することが最も優先すべき重要なことだと思います。

しかし、それができなければ「インターネットに接続できないから最新の Visual Studio や自動ビルド・自動テスト・自動デプロイは使えない」のではもったいない。これらはアジャイルなどと違って、顧客やプロジェクトの文化の変化を待たなくても、開発者の判断で導入できる部分です。どうしても仕方がない場合には、この手順を参考にインターネットに接続できない環境でも、Azure DevOps Server を活用してもらえれば、と思います。