はじめに
- 本記事ではUiPath Automation Suite v2023.4をAzure環境にてTerraformを利用してインストールする手順をまとめたものです。
- AWS環境での手順はこちらの記事をご参照ください。
- Automation Suiteはハードウェアおよびソフトウェアの要件に記載の通り、そこそこマシンスペックが必要(F16s_v2以上)なためインストールを試行している間にもそれなりに課金が発生($0.8560/時間~)しますのでご注意ください。
Automation Suiteとは?
- UiPathの各製品サービスを一まとめにしてユーザーが所有する環境に展開できる全部入りの製品です。v2022.10では次の製品サービスがサポートされています。
- Orchestrator
- Action Center
- AI Center
- Apps
- Automation Hub
- Automation Ops
- Data Service
- Document Understanding
- Insights
- Process Mining
- Automation Suite Robots
- Task Mining
- Test Manager
- 全部入りという意味ではSaaS型のAutomation Cloudも利用可能ですが、次のような利用上の課題が考えられます。
- インターネット経由でのアクセスのみ許可されており、専用線やVPNのみに接続を限定することはできません。
- ソースIPの制限を設けることはできますが、インターネット経由でのアクセスという点では変わりはありません。
- Automation CloudはUiPath社が管理するAzure基盤にマルチテナントで展開されており、現在のところ専有テナントで展開するオプションはありません。
- インターネット経由でのアクセスのみ許可されており、専用線やVPNのみに接続を限定することはできません。
- これらの課題を解決すべく、いわば「Automation Cloudのオンプレミス版」とも呼べるのがAutomation Suiteになります。UiPath社は2022年9月より、Business Automation Platform という戦略を打ち出しており、自動化領域の発見から開発、管理・運用、効果計測に至るまで一気通貫した製品群をプラットフォームとして提供しています。つまり「Business Automation Platformをオンプレミスで実現する製品がAutomation Suite」という位置づけになると筆者は捉えています。
Automation Suiteの構成
Azure環境での構成図
- 今回は検証環境としてシングル構成にてAutomation Suiteを展開します。構成図は次の通りです。
- Bastion: 踏み台サーバー兼作業用Windowsマシン
- WebAPサーバー: Automation SuiteをインストールするLinuxマシン (ソフトウェア要件より、現状はRHEL8.xのみサポート)
- Azure SQL Database: Automation Suiteの各製品サービスが使用するデータベース (複数利用)
- ストレージアカウント: Automation Suiteの各製品サービスのアプリケーションデータを格納するBlobストレージ (「オブジェクトストア」と呼ばれる)
-
プライベートDNSゾーン: Automation Suiteによって使用されるDNSレコードを作成 (今回は検証用に
lab.test
というローカルドメインを使用)
- WebAPサーバーからインターネットアクセスは可能とします。
- WebAPサーバーからAzure SQLとストレージアカウントへのアクセスにはそれぞれプライベートエンドポイントを使用します。
Automation Suiteのサイジング
- 利用するUiPath製品サービスの数に比例して、Automation Suiteのマシンスペック要件も高くなります。詳細はハードウェア要件をご確認ください。
- また キャパシティ計算ツール を利用して、利用する製品サービスに応じて必要なマシンスペックを詳細に見積もることができます。
- 今回は利用するUiPath製品サービスはOrchestratorとAutomation Hubとします。先ほどのキャパシティ計算ツールを使用すると次のように必要なAzureリソースが表示されます。
Automation Suiteの環境構築
Azureリソース作成
- これらを手作業で作成するには少々骨が折れるためTerraformにて展開したいと思います。Terraformの使い方に慣れていない方はこちらの記事を参照してTerraformの実行環境をセットアップしてください。
- AzureリソースをTerraformにて作成するためには Azure CLI をインストールします。
- 次のコマンドを一行ずつ実行することによって、リソースを作成するAzure ADテナントにログインし、サブスクリプションを切り替えます。もしくはサービスプリンシパルによってAzureにログインします。
az login --tenant "<Azure AD テナントID>" # 既定のブラウザーでサインイン az account set --subscription "<Azure AD テナントに紐づくサブスクリプション名>"
- Terraformは作成するリソースの単位、変数およびアウトプットなどによってファイルを分割した方が良いのですが、今回は分かりやすさを優先するためmain.tfという一つのファイルで保存して実行します。各local変数は環境に応じて値を変更します。
- res_prefix: 各Azureリソースのプレフィックス名
- rg_name: リソースグループ名
- location: リージョン
- tags: リソースグループに付けるタグ (省略可)
- storage_account: ストレージアカウント名
- vm_username: 踏み台サーバーとWebAPサーバーVMの管理者ユーザー名
- vm_password: 踏み台サーバーとWebAPサーバーVMの管理者パスワード
- web_hostname: WebAPサーバーのホスト名
- sql_hostname: Azure SQLサーバーのホスト名
- sql_username: Azure SQLサーバーの管理者ユーザー名
- sql_password: Azure SQLサーバーの管理者パスワード
- my_ip: 踏み台サーバーにRDPアクセスを許可するIPアドレス (作業マシンがインターネット接続しているグローバルIPアドレス確認して指定します)
- as_fqdn: Automation SuiteのFQDN
- as_vm_size: WebAPサーバーのマシンサイズ (最低でもStandard_F16s_v2、インストールする製品数が多い場合はStandard_F32s_v2)
main.tf (クリックして展開)
# Local variables (change them according to your environment)
locals {
res_prefix = "hidecha"
rg_name = "hidecha-rg"
location = "Japan East"
tags = {
Owner = "hidecha"
Project = "Qiita"
}
vnet_address = "10.1.0.0/16"
subnet_address = "10.1.0.0/24"
storage_account = "hidechastr"
vm_username = "vm_admin"
vm_password = "SuperSecretP@ssw0rd"
web_hostname = "web01"
sql_hostname = "hidechasql"
sql_username = "sql_admin"
sql_password = "SuperSecretP@ssw0rd"
my_ip = "104.19.251.9"
as_fqdn = "as.lab.test"
as_vm_size = "Standard_F16s_v2"
}
# Provider
provider "azurerm" {
features {}
}
# Create Resource Group
resource "azurerm_resource_group" "rg" {
name = local.rg_name
location = local.location
tags = local.tags
}
# Create Virtual Network
## VNET
resource "azurerm_virtual_network" "vnet" {
name = "${local.res_prefix}-vnet"
address_space = [local.vnet_address]
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
}
## Subnet
resource "azurerm_subnet" "subnet" {
name = "${local.res_prefix}-subnet"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = [local.subnet_address]
}
## Network Security Group
resource "azurerm_network_security_group" "nsg" {
name = "${local.res_prefix}-nsg"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
}
## Network Security Rule
resource "azurerm_network_security_rule" "nsg_rule" {
name = "RDP"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "3389"
source_address_prefix = local.my_ip
destination_address_prefix = "*"
resource_group_name = azurerm_resource_group.rg.name
network_security_group_name = azurerm_network_security_group.nsg.name
}
# Create Windows VM for Bastion
## Public IP
resource "azurerm_public_ip" "public_ip" {
name = "${local.res_prefix}-bastion-pip"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
allocation_method = "Static"
}
## Network Interface
resource "azurerm_network_interface" "vm_nic" {
name = "${local.res_prefix}-bastion-nic"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
enable_accelerated_networking = true
ip_configuration {
name = "ipconfig"
subnet_id = azurerm_subnet.subnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.public_ip.id
}
}
## Security Group to Network Interface Association
resource "azurerm_network_interface_security_group_association" "vm_sg_nic_association" {
network_interface_id = azurerm_network_interface.vm_nic.id
network_security_group_id = azurerm_network_security_group.nsg.id
}
## Windows VM
resource "azurerm_windows_virtual_machine" "vm_bastion" {
name = "${local.res_prefix}-bastion"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
size = "Standard_D2as_v4"
computer_name = "bastion"
admin_username = local.vm_username
admin_password = local.vm_password
network_interface_ids = [azurerm_network_interface.vm_nic.id]
os_disk {
caching = "ReadWrite"
storage_account_type = "StandardSSD_LRS"
}
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2022-datacenter-g2"
version = "latest"
}
}
# Azure SQL
## SQL Server
resource "azurerm_mssql_server" "sql_server" {
name = local.sql_hostname
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
version = "12.0"
administrator_login = local.sql_username
administrator_login_password = local.sql_password
public_network_access_enabled = false
}
## Private Endpoint for SQL Server
resource "azurerm_private_endpoint" "sql_server_endpoint" {
name = "${local.sql_hostname}-endpoint"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
subnet_id = azurerm_subnet.subnet.id
depends_on = [azurerm_mssql_server.sql_server]
private_service_connection {
name = "${local.sql_hostname}-private-conn"
private_connection_resource_id = azurerm_mssql_server.sql_server.id
subresource_names = ["sqlServer"]
is_manual_connection = false
}
}
data "azurerm_private_endpoint_connection" "sql_server_conn" {
name = azurerm_private_endpoint.sql_server_endpoint.name
resource_group_name = azurerm_resource_group.rg.name
}
## Private DNS Zone for SQL Server Private Endpoint
resource "azurerm_private_dns_zone" "sql_server_zone" {
name = "privatelink.database.windows.net"
resource_group_name = azurerm_resource_group.rg.name
depends_on = [azurerm_private_endpoint.sql_server_endpoint]
}
resource "azurerm_private_dns_zone_virtual_network_link" "sql_server_vnet_link" {
name = "${local.sql_hostname}-vnet-link"
resource_group_name = azurerm_resource_group.rg.name
private_dns_zone_name = azurerm_private_dns_zone.sql_server_zone.name
virtual_network_id = azurerm_virtual_network.vnet.id
}
resource "azurerm_private_dns_a_record" "sql_server_dns_record" {
name = azurerm_mssql_server.sql_server.name
zone_name = azurerm_private_dns_zone.sql_server_zone.name
resource_group_name = azurerm_resource_group.rg.name
ttl = 3600
records = [data.azurerm_private_endpoint_connection.sql_server_conn.private_service_connection[0].private_ip_address]
}
# Storage Account for Object Storage
## Storage Account
resource "azurerm_storage_account" "storage_account" {
name = local.storage_account
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
account_tier = "Standard"
account_replication_type = "LRS"
public_network_access_enabled = false
}
## Private Endpoint for Storage Account
resource "azurerm_private_endpoint" "storage_endpoint" {
name = "${local.storage_account}-endpoint"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
subnet_id = azurerm_subnet.subnet.id
depends_on = [azurerm_storage_account.storage_account]
private_service_connection {
name = "${local.storage_account}-private-conn"
private_connection_resource_id = azurerm_storage_account.storage_account.id
subresource_names = ["blob"]
is_manual_connection = false
}
}
data "azurerm_private_endpoint_connection" "storage_conn" {
name = azurerm_private_endpoint.storage_endpoint.name
resource_group_name = azurerm_resource_group.rg.name
}
## Private DNS Zone for Storage Account
resource "azurerm_private_dns_zone" "storage_zone" {
name = "privatelink.blob.core.windows.net"
resource_group_name = azurerm_resource_group.rg.name
depends_on = [azurerm_private_endpoint.storage_endpoint]
}
resource "azurerm_private_dns_zone_virtual_network_link" "storage_vnet_link" {
name = "${local.storage_account}-vnet-link"
resource_group_name = azurerm_resource_group.rg.name
private_dns_zone_name = azurerm_private_dns_zone.storage_zone.name
virtual_network_id = azurerm_virtual_network.vnet.id
}
resource "azurerm_private_dns_a_record" "storage_account_dns_record" {
name = azurerm_storage_account.storage_account.name
zone_name = azurerm_private_dns_zone.storage_zone.name
resource_group_name = azurerm_resource_group.rg.name
ttl = 3600
records = [data.azurerm_private_endpoint_connection.storage_conn.private_service_connection[0].private_ip_address]
}
# RHEL Virtual Machine for Automation Suite WebAP server
## Network Interface
resource "azurerm_network_interface" "web_server_nic" {
name = "${local.res_prefix}-web-nic"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
enable_accelerated_networking = true
ip_configuration {
name = "web_server_nic_configuration"
subnet_id = azurerm_subnet.subnet.id
private_ip_address_allocation = "Dynamic"
}
}
## Security group to Network Interface Association
resource "azurerm_network_interface_security_group_association" "as_sg_nic_association" {
network_interface_id = azurerm_network_interface.web_server_nic.id
network_security_group_id = azurerm_network_security_group.nsg.id
}
## RHEL VM
resource "azurerm_linux_virtual_machine" "web_server_vm" {
name = "${local.res_prefix}-${local.web_hostname}"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
network_interface_ids = [azurerm_network_interface.web_server_nic.id]
size = local.as_vm_size
os_disk {
name = "${local.res_prefix}-${local.web_hostname}_OsDisk"
caching = "ReadWrite"
storage_account_type = "StandardSSD_LRS"
}
source_image_reference {
publisher = "RedHat"
offer = "RHEL"
sku = "86-gen2"
version = "latest"
}
computer_name = local.web_hostname
admin_username = local.vm_username
admin_password = local.vm_password
disable_password_authentication = false
}
### Managed disks
locals {
disk_sizes = [256, 16, 512]
}
resource "azurerm_managed_disk" "web_server_disk" {
count = length(local.disk_sizes)
name = "${local.res_prefix}-${local.web_hostname}_DataDisk_${count.index}"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
storage_account_type = "StandardSSD_LRS"
create_option = "Empty"
disk_size_gb = element(local.disk_sizes, count.index)
}
### Managed disk to VM attachment
resource "azurerm_virtual_machine_data_disk_attachment" "web_server_disk_attach" {
count = length(local.disk_sizes)
managed_disk_id = element(azurerm_managed_disk.web_server_disk.*.id, count.index)
virtual_machine_id = azurerm_linux_virtual_machine.web_server_vm.id
lun = count.index
caching = "ReadWrite"
}
# Private DNS Zone for Automation Suite WebAP
## Private DNS Zone
resource "azurerm_private_dns_zone" "web_server_zone" {
name = local.as_fqdn
resource_group_name = azurerm_resource_group.rg.name
}
## DNS Zone to VNET Network Link
resource "azurerm_private_dns_zone_virtual_network_link" "web_server_vnet_link" {
name = "${local.res_prefix}-web-link"
resource_group_name = azurerm_resource_group.rg.name
private_dns_zone_name = azurerm_private_dns_zone.web_server_zone.name
virtual_network_id = azurerm_virtual_network.vnet.id
}
## DNS Records for Automation Suite WebAP
resource "azurerm_private_dns_a_record" "web_server_dns_a_record" {
name = "@"
zone_name = azurerm_private_dns_zone.web_server_zone.name
resource_group_name = azurerm_resource_group.rg.name
ttl = 3600
records = [azurerm_linux_virtual_machine.web_server_vm.private_ip_address]
}
resource "azurerm_private_dns_cname_record" "web_server_dns_cname_record" {
for_each = toset(["alm", "monitoring", "objectstore", "registry", "insights"])
name = each.key
zone_name = azurerm_private_dns_zone.web_server_zone.name
resource_group_name = azurerm_resource_group.rg.name
ttl = 3600
record = local.as_fqdn
}
output "bastion_public_ip_address" {
value = azurerm_public_ip.public_ip.ip_address
}
output "web_server_private_ip_address" {
value = azurerm_linux_virtual_machine.web_server_vm.private_ip_address
}
output "sqlserver_hostname" {
value = azurerm_mssql_server.sql_server.fully_qualified_domain_name
}
-
準備が整いましたらmain.tfが配置されたディレクトリに移動し、次のコマンドを一行ずつ実行し、Automation Suiteに必要なAzureリソースを展開します。
terraform init terraform plan -out main.tfplan terraform apply main.tfplan
-
Terraformを用いずに手動でAzureリソースを作成することもできます。詳細な手順は Azure インフラストラクチャのセットアップ例 をご参照ください。
Automation Suiteインストール前準備
- Azureリソースが作成できましたら、Automation Suiteのインストールに必要となる設定や前提条件となるパッケージなどをインストールします。
- まず最初に踏み台サーバー(Bastion)にRDPでアクセスし、SSHクライアント(ここでは TeraTerm 5 を使用)をインストールします。Automation SuiteのWebAPサーバーにSSHでアクセスします。
- ディスクを構成します。
- パーティショニング用スクリプトをダウンロードして実行権限を付与します。
wget https://download.uipath.com/automation-suite/configureUiPathDisks.sh chmod +x configureUiPathDisks.sh
- マウントしているマネージディスクのデバイス名を確認するために
sudo lsblk -dip
を実行します。たとえば次のように出力されます。
/dev/sda 8:0 0 64G 0 disk
/dev/sdb 8:16 0 128G 0 disk
/dev/sdc 8:32 0 16G 0 disk
/dev/sdd 8:48 0 256G 0 disk
/dev/sde 8:64 0 512G 0 disk
/dev/sr0 11:0 1 628K 0 rom- 次のコマンドでパーティショニングを行います。各オプションは
--etcd-disk-name <ディスクサイズ16GB>
,--cluster-disk-name <ディスクサイズ256GB>
,--data-disk-name <ディスクサイズ512GB>
となるようにデバイス名を指定します。
sudo ./configureUiPathDisks.sh --node-type server --install-type online \ --etcd-disk-name /dev/sdc \ --cluster-disk-name /dev/sdd \ --data-disk-name /dev/sde
- データディスクがSSDとして認識されるように次のコマンドを実行します。
sde
は実際のデータディスク(512GB)のデバイス名に置き換えます。
sudo su - echo "0" > "/sys/block/sde/queue/rotational" echo "KERNEL==\"sde\", ATTR{queue/rotational}=\"0\"" >> "/etc/udev/rules.d/99-ceph-raw-osd-mark-ssd.rules" udevadm control --reload udevadm trigger exit
- 次のコマンドを実行してAutomation Suiteに必要となるパッケージをインストールします。
sudo dnf -y install iscsi-initiator-utils nfs-utils rpcbind util-linux nmap-ncat openssl httpd-tools gettext zstd podman bind-utils wget unzip conmon
Automation Suiteインストールの実行
- ここまででようやくAutomation Suiteをインストールする前準備が整いました。WebAPサーバーにSSHでアクセスして次のコマンドを実行し、Automation Suiteのインタラクティブインストーラーを実行します。
-
AS_VER
変数でインストールするバージョンを定義します。下記例では2023.4.1をインストールします。
AS_VER=2023.4.1 wget https://download.uipath.com/automation-suite/${AS_VER}/installUiPathAS.sh chmod +x installUiPathAS.sh sudo ./installUiPathAS.sh
-
- License Agreementに同意します。
- Single-node展開を選択します。
- インストールを継続し、Onlineインストールを選択します。インストールする製品を選択します。
- インストールする製品を番号で指定します。カンマ区切りで複数指定できます。今回はAutomation HubとOrchestratorをインストールするため
4,9
と指定します。製品選択を確認の上、続行します。
- Automation SuiteのFQDN(例: as.lab.test)を入力し、オブジェクトストアとしてAzure Storage Accountを指定します。
- 今回はマネージドIdentityは使用しません。先ほどメモしたストレージアカウントの情報を入力します。ストレージアカウント内に作成されるバケット(Blobコンテナ)名が表示されます。
- 次にSQL Serverへの接続情報を入力します。Kerberos認証は使用せず、データベースは自動作成するように設定します。
- サーバー証明書のルート証明書のパスを訊かれますが空白で続行します。サーバー証明書はインストール後に入れ替えが可能です。
- インストールオプションの確認画面が表示されます。問題なければ続行します。(設定変更も可能です)
- インストールオプションは構成ファイルとして
/opt/UiPathAutomationSuite/cluster_config.json
に保存されます。このファイルを編集して詳細にインストールオプションをカスタマイズすることもできます。詳細は 手動: 高度なインストール をご参照ください。 - 最終確認の画面が表示されますので、続行するとインストールが開始されます。
- インストールは1~2時間ほどかかります。途中でエラーが発生した場合にはエラーメッセージに出力されるインストールログファイルを確認します。
- インストールが完了すると、管理者パスワードの取得方法などの手順が表示されます。
Automation Suiteインストール後の作業
Automation Suite管理画面へのログイン
- ログインのためのパスワードを取得するためにWebAPサーバーにSSHでアクセスして次のコマンドを実行します。デフォルト組織とホスト組織の管理者の初期パスワードは同じです。初回ログイン時に変更することをお勧めします。
sudo su - export KUBECONFIG=/etc/rancher/rke2/rke2.yaml PATH=$PATH:/var/lib/rancher/rke2/bin kubectl get secrets/platform-service-secrets -n uipath -o "jsonpath={.data['identity\.hostAdminPassword']}" | base64 --decode
- ホスト組織は組織を管理するための特別な組織です。ホスト組織にシステム管理者でログインして、新しい組織を作成したり、ライセンスを一元管理して各組織に割り当てることができます。詳細はホストの管理 ガイドの各ページをご参照ください。
- 今回は自動的に作成されるデフォルト組織にログインしてみます。
- Orchestrator管理画面にアクセスしてみます。Automation Cloudとほぼ同じ操作感です。
- Automation Hubの管理画面にアクセスするにはライセンスアクティベーションが必要です。
- トライアルライセンスなどについてはUiPath社にお問い合わせください。
- ライセンスモデルについてはWebガイドをご参照ください。
- ライセンスコードを入手後、アクティベーションを行います。
- Automation Hubが含まれるライセンスをアクティベーションしますと、DefaultTenantのサービス画面にてAutomation Hubのサービスを追加できるようになります。
- 以前はAutomation Cloudでのみ利用可能だったAutomation Hubが自前のAzure環境でも構築することができました。
- ユーザーの言語設定によってUIを日本語に切り替えることも可能です。
サーバー証明書の入れ替え
- Automation Suiteのインストール時に自動作成される自己署名証明書の有効期限は90日間です。有効期限が切れる前に別のサーバー証明書を準備し、入れ替えを行う必要があります。詳細な手順は 証明書を管理する をご参照ください。
おわりに
- 今回は難易度が高いと言われているAutomation Suiteのインストール手順について説明をしました。
- UiPathのすべての製品を一つの環境で展開できるのがAutomation Suiteの大きなメリットです。ご関心のある方はぜひAutomation Suiteのインストールにチャレンジしていただけると幸いです!