OracleCloud上のWindowsServerを自動セットアップする手順

# 概要
OracleCloudの管理画面とWindowsリモートデスクトップを使わずに

 - WindowsServerインスタンス作成
 - サクラエディタインストール
 - IISインストール
 - .NET Frameworkインストール
 - WebDeployインストール
 - ASP.NET(ODP.NET)アプリケーション デプロイ
 - OracleDatabase19cインストール

してみた

# 何が嬉しい

 - OracleCloud管理画面にアクセスしなくてよい
 - 面倒なリモートデスクトップを使わずに自動セットアップできる
 - 複数台のWindowsサーバをまとめて自動セットアップできる
 - sysprep済のイメージ使いまわし運用を回避できる
 - Ansibleを使うことにより冪等性を担保できる

など

# 構成

 **Ansible用のLinuxインスタンス**
 - OracleLinux7.6 x 1
 
 **セットアップ対象のWindowsインスタンス**
 - WindowsServer2016 x 2

# 流れ

 1. Ansible用のLinuxインスタンスを作成
 2. sshでLinuxインスタンスにログイン
 3. OracleCloud CLIツールをインストール
 4. CLIツールを使い、WindowsServer x 2を作成
 5. LinuxインスタンスにAnsibleをインストール
 6. WindowsServer x 2に適用するymlを作成
 7. WindowsServer x 2にAnsible適用
 8. WindowsServer動作確認
 
 ※ 4.ですが、今回はOracleCloud CLIツールを使った例です
    下記のようなOracleCloud terraform providerを使っても簡単にセットアップできます
    https://github.com/terraform-providers/terraform-provider-oci

# 手順

### 1. Ansible用のLinuxインスタンスを作成
省きます
※この手順ではOracleCloudで提供しているOracleLinux7.6を使用

### 2. sshでLinuxインスタンスにログイン

```shell
ssh -l opc 132.145.xxx.xxx
```

### 3. OracleCloud CLIツールをインストール

```shell
mkdir ~/.oci
cat << _EOT_ > ~/.oci/key.pem
-----BEGIN RSA PRIVATE KEY-----
####### Paste Your key ########
------END RSA PRIVATE KEY------
_EOT_

bash -c "$(curl -L https://raw.githubusercontent.com/oracle/oci-cli/master/scripts/install/install.sh)"
exec -l $SHELL

cat << _EOT_ > ~/.oci/config
[DEFAULT]
fingerprint=d3:3a:8c:87:9f:2a:ca:31:fd:c3:4f:da:d3:xx:xx:xx
key_file=/home/opc/.oci/key.pem
region=ap-tokyo-1
user=ocid1.user.oc1..aaaaaaaaupet7b3vwjpq3qn5xhgrz2kovycplu35yv5wo3tnhy2vzivxxxxx
tenancy=ocid1.tenancy.oc1..aaaaaaaaksusyefovxt64bsovu523r5ez6qz25pcnqjw2a243qjmft5xxxxx
_EOT_

chmod 400 ~/.oci/key.pem
chmod 400 ~/.oci/config
```

### 4. CLIツールを使い、WindowsServer x 2を作成

```shell
COMPAERMENT_ID="ocid1.compartment.oc1..aaaaaaaatsglzanirklya6nivva4vx6ckygn7jqoxl74mcsik45lsxxxxx"
AVAILABILITY_DOMAIN="HOAM:AP-TOKYO-1-AD-1"
VCN_ID="ocid1.vcn.oc1.ap-tokyo-1.aaaaaaaazl2mtgy3vjcvxam7ejxqfv4ip2qe7y7do2dzegbzz2hfvqxxxxx"
SUBNET_ID="ocid1.subnet.oc1.ap-tokyo-1.aaaaaaaal6wcvptfbgzrelimw4oemvvr4f4ntgiik4huvi3zdnvwiqxxxxx"
# Windows-Server-2016-Standard-Edition-VM-Gen2-2019.06.13-0
IMAGE_ID="ocid1.image.oc1.ap-tokyo-1.aaaaaaaaol3wo2l5pcsog3vw23washabefsbegnnl7mdpox5taw577t2dycq"

cat << _EOT_ > cloudbase-init.ps
#ps1_sysnative
net user opc "Y0urP@ssW0rd!"
_EOT_

for i in {1..2} ; do
  INSTANCE_NAME=Windows${i}
  oci compute instance launch \
  --availability-domain ${AVAILABILITY_DOMAIN} \
  --fault-domain FAULT-DOMAIN-1 \
  --shape VM.Standard2.1 \
  --display-name ${INSTANCE_NAME} \
  --hostname-label ${INSTANCE_NAME} \
  --image-id ${IMAGE_ID} \
  --subnet-id ${SUBNET_ID} \
  --assign-public-ip true \
  --compartment-id ${COMPAERMENT_ID} \
  --user-data-file cloudbase-init.ps \
  > /tmp/oci_cli_${INSTANCE_NAME}.log 2>&1 
done

# 作成状況確認
while true; do 
  for i in {1..2} ; do
    INSTANCE_NAME=Windows${i}
    INSTANCE_ID=`cat /tmp/oci_cli_${INSTANCE_NAME}.log  |jq -r '.data.id'`
    STATUS=`oci compute instance get --instance-id ${INSTANCE_ID} | jq -r '.data."lifecycle-state"'`
    INSTANCE_PUBLIC_IP=`oci compute instance list-vnics --instance-id ${INSTANCE_ID} | jq -r '.data[]."public-ip"'`
    INSTANCE_PRIVATE_IP=`oci compute instance list-vnics --instance-id ${INSTANCE_ID} | jq -r '.data[]."private-ip"'`
    echo ${INSTANCE_NAME}:${STATUS},IP:${INSTANCE_PUBLIC_IP},${INSTANCE_PRIVATE_IP}
    sleep 1s; 
  done
done

# 下記のような表示が出力されていればインスタンス作成中
#
# Windows1:PROVISIONING,IP:132.145.xxx.1,10.0.0.2
# Windows2:PROVISIONING,IP:132.145.xxx.2,10.0.0.3
# Windows1:PROVISIONING,IP:132.145.xxx.1,10.0.0.2
# Windows2:PROVISIONING,IP:132.145.xxx.2,10.0.0.3
#
# 「RUNNING」に変わったらインスタンス作成完了
# Windows1:RUNNING,IP:132.145.xxx.1,10.0.0.2
# Windows2:RUNNING,IP:132.145.xxx.2,10.0.0.3
# Windows1:RUNNING,IP:132.145.xxx.1,10.0.0.2
```


### 5. LinuxインスタンスにAnsibleをインストール

```shell
sudo yum localinstall -y https://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/e/epel-release-7-11.noarch.rpm
sudo yum install -y https://centos7.iuscommunity.org/ius-release.rpm
sudo yum install -y python36u python36u-libs python36u-devel python36u-pip
path_pip=`which pip3.6`
sudo ln -s ${path_pip} /usr/local/bin/pip
pip --version

# 下記のような表示が出力されればOK
# pip 9.0.1 from /usr/lib/python3.6/site-packages (python 3.6)

sudo /usr/local/bin/pip install pywinrm
sudo /usr/local/bin/pip install ansible
ansible --version

# 下記のような表示が出力されればOK
# ansible 2.8.2
# config file = None
# configured module search path = ['/home/opc/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
# ansible python module location = /usr/lib/python3.6/site-packages/ansible
# executable location = /usr/bin/ansible
# python version = 3.6.8 (default, May  2 2019, 20:40:44) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]

cat << _EOT_ > .ansible.cfg
[defaults]
forks = 100
host_key_checking = False
[paramiko_connection]
record_host_keys = False
pty = False
deprecation_warnings = False
[ssh_connection]
transport = ssh
ssh_args = -o ControlMaster=auto -o ControlPersist=30s
pipelining = True
[accelerate]
accelerate_port = 5099
accelerate_timeout = 30
accelerate_connect_timeout = 5.0
accelerate_daemon_timeout = 30
accelerate_multi_key = yes
_EOT_
```

### 6. WindowsServer x 2に適用するymlを作成

```shell
cat << _EOT_ > hosts
[windows]
### 4. CLIツールを使い、WindowsServer x 2を作成
### 作成状況確認
### で、取得したプライベートIPを設定
10.0.0.3
10.0.0.4

[windows:vars]
ansible_user=opc
ansible_password=Y0urP@ssW0rd!
ansible_port=5986
ansible_connection=winrm
ansible_winrm_server_cert_validation=ignore
_EOT_

cat << _EOT_ > setup.yml
- hosts: windows
  tasks:
  - name: Download SakuraEditor
    win_get_url:
      url: 'https://objectstorage.ap-tokyo-1.oraclecloud.com/n/xxxxx/b/xxxxx/o/sakura_install2-2-0-1.exe'
      dest: 'C:\Users\opc\Downloads\'

  - name: Install SakuraEditor
    win_package:
      path: C:\Users\opc\Downloads\sakura_install2-2-0-1.exe
      product_id: sakura_install2-2-0-1.exe
      arguments:
      - /VERYSILENT
      - /SP-
      log_path: C:\Users\opc\Downloads\WebDeploy_amd64_ja-JP.log

  - name: Install Web-Server(IIS)
    win_feature:
      name: Web-Server
      state: present
      include_sub_features: yes
      include_management_tools: yes
    register: win_feature

  - name: Reboot if installing Web-Server feature requires it
    win_reboot:
    when: win_feature.reboot_required

  - name: Download WebDeploy
    win_get_url:
      url: https://objectstorage.ap-tokyo-1.oraclecloud.com/n/xxxxx/b/xxxxx/o/WebDeploy_amd64_ja-JP.msi
      dest: C:\Users\opc\Downloads\

  - name: Install WebDeploy
    win_package:
      path: C:\Users\opc\Downloads\WebDeploy_amd64_ja-JP.msi
      arguments:
      - /quiet
      - /passive
      - /norestart
      log_path: C:\Users\opc\Downloads\WebDeploy_amd64_ja-JP.log

  - name: Download .NET4.8
    win_get_url:
      url: https://objectstorage.ap-tokyo-1.oraclecloud.com/n/xxxxx/b/xxxxx/o/ndp48-web.exe
      dest: 'C:\Users\opc\Downloads\'

  - name: Install .NET4.8
    win_package:
      path: C:\Users\opc\Downloads\ndp48-web.exe
      product_id: ndp48-web.exe
      arguments:
      - /q
      - /norestart
      log_path: C:\Users\opc\Downloads\ndp48-web.log

  - name: Download WebApplication1
    win_get_url:
      url: https://objectstorage.ap-tokyo-1.oraclecloud.com/n/xxxxx/b/xxxxx/o/WebApplication1.zip
      dest: C:\Users\opc\Downloads\

  - name: Deploy WebApplication1
    win_command: '"C:\Program Files (x86)\IIS\Microsoft Web Deploy V3\msdeploy.exe" -verb:sync -source:package="C:\Users\opc\Downloads\WebApplication1.zip" -dest:auto -setParam:"IIS Web Application Name"="Default Web Site"'

  - name: Download OracleDB 19c
    win_get_url:
      url: https://objectstorage.ap-tokyo-1.oraclecloud.com/n/xxxxx/b/xxxxx/o/WINDOWS.X64_193000_db_home.zip
      dest: C:\Users\opc\Downloads\

  - name: Download ResponseFile
    win_get_url:
      url: https://objectstorage.ap-tokyo-1.oraclecloud.com/n/xxxxx/b/xxxxx/o/db.rsp
      dest: C:\Users\opc\Downloads\

  - name: Unzip OracleDB 19c
    win_unzip:
      src: C:\Users\opc\Downloads\WINDOWS.X64_193000_db_home.zip
      dest: C:\Users\opc\Downloads\WINDOWS.X64_193000_db_home

  - name: Install OracleDB 19c
    win_command: C:\Users\opc\Downloads\WINDOWS.X64_193000_db_home\setup.exe -silent -responseFile C:\Users\opc\Downloads\db.rsp

  - name: Edit Web.config
    win_lineinfile:
      path: C:\inetpub\wwwroot\Web.config
      regexp: '.*\<dataSource alias="DataSource" descriptor="\(DESCRIPTION=\(ADDRESS=\(PROTOCOL=tcp\)\(HOST=localhost\)\(PORT=1521\)\)\(CONNECT_DATA=\(SERVICE_NAME=ORCL\)\)\) "/>'
      line: '     <dataSource alias="DataSource" descriptor="(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST={{ ansible_ip_addresses[0] }})(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL))) "/>'
_EOT_
```

### 7. WindowsServer x 2にAnsible適用

```shell
# 接続確認
ansible -i hosts all -m win_ping

# 下記のような表示が出力されればOK
# 
# 10.0.0.2 | SUCCESS => {
#     "changed": false,
#     "ping": "pong"
# }
# 10.0.0.3 | SUCCESS => {
#     "changed": false,
#     "ping": "pong"
# }

# Ansible適用
ansible-playbook -i hosts setup.yml -D

# 下記のような表示が出力されればOK
# 
# PLAY [windows] **********************************************************************************************************************************************************************************************************************
# 
# 
# TASK [Gathering Facts] **************************************************************************************************************************************************************************************************************
# 
# ok: [10.0.0.2]
# ok: [10.0.0.3]
# 
# TASK [Download SakuraEditor] ********************************************************************************************************************************************************************************************************
# 
# changed: [10.0.0.2]
# changed: [10.0.0.3]
# 
# TASK [Install SakuraEditor] *********************************************************************************************************************************************************************************************************
# 
# changed: [10.0.0.2]
# changed: [10.0.0.3]
# 
# TASK [Install Web-Server(IIS)] ******************************************************************************************************************************************************************************************************
# 
# changed: [10.0.0.2]
# changed: [10.0.0.3]
# 
# TASK [Reboot if installing Web-Server feature requires it] **************************************************************************************************************************************************************************
# 
# skipping: [10.0.0.2]
# skipping: [10.0.0.3]
# 
# TASK [Download WebDeploy] ***********************************************************************************************************************************************************************************************************
# 
# changed: [10.0.0.2]
# changed: [10.0.0.3]
# 
# TASK [Install WebDeploy] ************************************************************************************************************************************************************************************************************
# 
# changed: [10.0.0.2]
# changed: [10.0.0.3]
# 
# TASK [Download .NET4.8] *************************************************************************************************************************************************************************************************************
# 
# changed: [10.0.0.2]
# changed: [10.0.0.3]
# 
# TASK [Install .NET4.8] **************************************************************************************************************************************************************************************************************
# 
# changed: [10.0.0.3]
# changed: [10.0.0.2]
# 
# TASK [Download WebApplication1] *****************************************************************************************************************************************************************************************************
# 
# changed: [10.0.0.2]
# changed: [10.0.0.3]
# 
# TASK [Deploy WebApplication1] *******************************************************************************************************************************************************************************************************
# 
# changed: [10.0.0.2]
# changed: [10.0.0.3]
# 
# TASK [Download OracleDB 19c] ********************************************************************************************************************************************************************************************************
# 
# changed: [10.0.0.2]
# changed: [10.0.0.3]
# 
# TASK [Download ResponseFile] ********************************************************************************************************************************************************************************************************
# 
# changed: [10.0.0.3]
# changed: [10.0.0.2]
# 
# TASK [Unzip OracleDB 19c] ***********************************************************************************************************************************************************************************************************
# 
# changed: [10.0.0.2]
# changed: [10.0.0.3]
# 
# TASK [Install OracleDB 19c] *********************************************************************************************************************************************************************************************************
# 
# changed: [10.0.0.2]
# changed: [10.0.0.3]
# 
# TASK [Edit Web.config] **************************************************************************************************************************************************************************************************************
# 
# --- before
# +++ after
# @@ -74,7 +74,7 @@
#    <oracle.manageddataaccess.client>
#      <version number="*">
#        <dataSources>
# -        <dataSource alias="DataSource" descriptor="(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL))) "/>
# +     <dataSource alias="DataSource" descriptor="(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=10.0.0.2)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL))) "/>
#        </dataSources>
#      </version>
#    </oracle.manageddataaccess.client>
# 
# changed: [10.0.0.2]
# --- before
# +++ after
# @@ -74,7 +74,7 @@
#    <oracle.manageddataaccess.client>
#      <version number="*">
#        <dataSources>
# -        <dataSource alias="DataSource" descriptor="(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL))) "/>
# +     <dataSource alias="DataSource" descriptor="(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=10.0.0.3)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCL))) "/>
#        </dataSources>
#      </version>
#    </oracle.manageddataaccess.client>
# 
# changed: [10.0.0.3]
# 
# PLAY RECAP **************************************************************************************************************************************************************************************************************************
# 
# 10.0.0.2                : ok=15   changed=14   unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
# 10.0.0.3                : ok=15   changed=14   unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

```


### 8. WindowsServer動作確認

```shell
### 4. CLIツールを使い、WindowsServer x 2を作成
### 作成状況確認
### で、取得したパブリックIPもしくはプライベートIPにアクセス
curl 132.145.xxx.1 --head
curl 132.145.xxx.2 --head

# それぞれ下記のような表示が出力されればOK
# HTTP/1.1 200 OK
# Cache-Control: private
# Content-Length: 3492
# Content-Type: text/html; charset=utf-8
# Server: Microsoft-IIS/10.0
# X-AspNetMvc-Version: 5.2
# X-AspNet-Version: 4.0.30319
# X-Powered-By: ASP.NET 
```

# 参考URL
 - https://docs.cloud.oracle.com/iaas/tools/oci-cli/latest/oci_cli_docs/
 - https://docs.ansible.com/ansible/latest/index.html