Oracle Cloud LoadBalancer を cliで 作成して、2台のApacheへ負荷分散

# はじめに

Oracle Cloud の勉強の一環で、公式のチュートリアルを基に進めていきます。公式のチュートリアルでは日本語、かつ、GUI操作の内容となっています。わかりやすく書かれているので、基本は[こちら](https://community.oracle.com/docs/DOC-1019313)を参照していただけるとよいと思います。

このQiitaの記事は、上記のチュートリアルを CLI であえて実施した備忘録として書きます。
CLI の理由は、GUIと比べて再現性や再実行性が高いのと、**なんとなくかっこいいから**



# 今回のテーマ

ロードバランサーでWebサーバーを負荷分散する
https://community.oracle.com/docs/DOC-1019312




# 前提作業

## oci cliの導入

oci cli と jq コマンドを使用可能なこと。次のQiita記事で導入した手順を書いています
https://qiita.com/sugimount/items/63a8cfe1163030ae8804



## OCI DNSでドメイン連携済み

お名前.com などで購入したドメインと、OCI DNSを連携している必要があります

参照：https://qiita.com/sugimount/items/7d14ca7185d87c9763ff







# 仮想ネットワーク(VCN)の作成

[前回](https://qiita.com/sugimount/items/8d077f785a8fe1dc7971) の記事を参考に、Public Subnet を2個作成します。



# 2個のInstance作成して Apache を導入

## Instance作成

こちらも、[前回](https://qiita.com/sugimount/items/c714ab58d9aedf0b86ce) の記事を参考に、2個のInstanceを作成します。

参考：自分の環境でのコマンド

```
set vcn_ocid (oci network vcn list | jq -r '.data | map(select(.["display-name"] == "TutorialVCN"))[].id')
set subnet2_ocid (oci network subnet list --vcn-id $vcn_ocid | jq -r '.data | map(select(.["display-name"] == "tutorial_subnet2"))[].id')
set subnet3_ocid (oci network subnet list --vcn-id $vcn_ocid | jq -r '.data | map(select(.["display-name"] == "tutorial_subnet3"))[].id')
set oraclelinux76_ocid (echo ocid1.image.oc1.iad.aaaaaaaawufnve5jxze4xf7orejupw5iq3pms6cuadzjc7klojix6vmk42va)
set ubuntu1804_ocid (echo ocid1.image.oc1.iad.aaaaaaaahh6wjs5qp2sieliieujdnih7eyxt32ets3nuiifzjjfkqnbelcra)
```



1個目

```
oci compute instance launch \
--availability-domain AJtg:US-ASHBURN-AD-2 \
--fault-domain FAULT-DOMAIN-1 \
--shape VM.Standard2.1 \
--display-name web_1 \
--hostname-label web-1 \
--image-id $oraclelinux76_ocid \
--subnet-id $subnet2_ocid \
--assign-public-ip true \
--private-ip 172.16.2.2 \
--ssh-authorized-keys-file ~/.ssh/id_rsa.pub
```



2個目

```
oci compute instance launch \
--availability-domain AJtg:US-ASHBURN-AD-3 \
--fault-domain FAULT-DOMAIN-1 \
--shape VM.Standard2.1 \
--display-name web_2 \
--hostname-label web-2 \
--image-id $oraclelinux76_ocid \
--subnet-id $subnet3_ocid \
--assign-public-ip true \
--private-ip 172.16.3.2 \
--ssh-authorized-keys-file ~/.ssh/id_rsa.pub
```



## Apache 導入

作成した2台の Oracle Linux 7.6 の Instance へ Apache を導入します

```
sudo yum -y install httpd
sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --reload
sudo systemctl start httpd
sudo systemctl enable httpd
```



htmlファイルをそれぞれのhostがわかるように作成します

```
sudo su -
echo 'Web Server 1' >> /var/www/html/index.html
exit
```

```
sudo su -
echo 'Web Server 2' >> /var/www/html/index.html
exit
```



# LoadBalancer用のSubnet作成

## Instance側のSecurity Listを更新

http 80 を通すために更新します。oci cli による更新は、既存のルールと追加したいルールの両方ともを指定する必要があるため、まずは既存のルールを確認します。

```
> oci network security-list list --vcn-id $vcn_ocid --display-name "Default Security List for TutorialVCN" | jq -r '.data[0]."ingress-security-rules"'
[
  {
    "icmp-options": null,
    "is-stateless": false,
    "protocol": "6",
    "source": "0.0.0.0/0",
    "source-type": "CIDR_BLOCK",
    "tcp-options": {
      "destination-port-range": {
        "max": 22,
        "min": 22
      },
      "source-port-range": null
    },
    "udp-options": null
  },
  {
    "icmp-options": {
      "code": 4,
      "type": 3
    },
    "is-stateless": false,
    "protocol": "1",
    "source": "0.0.0.0/0",
    "source-type": "CIDR_BLOCK",
    "tcp-options": null,
    "udp-options": null
  },
  {
    "icmp-options": null,
    "is-stateless": false,
    "protocol": "1",
    "source": "172.16.0.0/16",
    "source-type": "CIDR_BLOCK",
    "tcp-options": null,
    "udp-options": null
  }
]
```



上記結果の "ingress-security-rules" の値を残しつつ、http80とhttp443を通信許可する設定を入れます

```
mkdir ~/workdir
string trim '
[
  {
    "icmp-options": null,
    "is-stateless": false,
    "protocol": "6",
    "source": "0.0.0.0/0",
    "source-type": "CIDR_BLOCK",
    "tcp-options": {
      "destination-port-range": {
        "max": 22,
        "min": 22
      },
      "source-port-range": null
    },
    "udp-options": null
  },
  {
    "icmp-options": {
      "code": 4,
      "type": 3
    },
    "is-stateless": false,
    "protocol": "1",
    "source": "0.0.0.0/0",
    "source-type": "CIDR_BLOCK",
    "tcp-options": null,
    "udp-options": null
  },
  {
    "icmp-options": null,
    "is-stateless": false,
    "protocol": "1",
    "source": "172.16.0.0/16",
    "source-type": "CIDR_BLOCK",
    "tcp-options": null,
    "udp-options": null
  },
  {
    "icmp-options": null,
    "is-stateless": false,
    "protocol": "6",
    "source": "172.16.0.0/16",
    "source-type": "CIDR_BLOCK",
    "tcp-options": {
      "destination-port-range": {
        "max": 80,
        "min": 80
      },
      "source-port-range": null
    },
    "udp-options": null
  },
  {
    "icmp-options": null,
    "is-stateless": false,
    "protocol": "6",
    "source": "172.16.0.0/16",
    "source-type": "CIDR_BLOCK",
    "tcp-options": {
      "destination-port-range": {
        "max": 443,
        "min": 443
      },
      "source-port-range": null
    },
    "udp-options": null
  }
]
' > ~/workdir/update-default-securitylist.json
```



Update対象のSecurity ListのOCIDを変数に格納

```
set securitylist_ocid (oci network security-list list --vcn-id $vcn_ocid --display-name "Default Security List for TutorialVCN" | jq -r '.data[0].id')
```



Security List を更新します

```
oci network security-list update --security-list-id $securitylist_ocid --ingress-security-rules file://~/workdir/update-default-securitylist.json --force
```



## Security Listの作成

LB用のSecurity List を作成します。
ちなみに、LBに設定を行うことで、適切なルールが自動設定されるとチュートリアルに書いていましたが、自分の環境では動作しませんでした（なぜ・・・）

IngressとEgress ルール用のJSONファイルを生成します。

```
mkdir ~/workdir
string trim '
[
  {
    "icmp-options": null,
    "is-stateless": false,
    "protocol": "6",
    "source": "0.0.0.0/0",
    "source-type": "CIDR_BLOCK",
    "tcp-options": {
      "destination-port-range": {
        "max": 80,
        "min": 80
      },
      "source-port-range": null
    },
    "udp-options": null
  },
  {
    "icmp-options": null,
    "is-stateless": false,
    "protocol": "6",
    "source": "0.0.0.0/0",
    "source-type": "CIDR_BLOCK",
    "tcp-options": {
      "destination-port-range": {
        "max": 443,
        "min": 443
      },
      "source-port-range": null
    },
    "udp-options": null
  }
]
' > ~/workdir/create-httplb1-securitylist-ingress.json

string trim '
[
  {
    "destination": "0.0.0.0/0",
    "destination-type": "CIDR_BLOCK",
    "icmp-options": null,
    "is-stateless": false,
    "protocol": "all",
    "tcp-options": null,
    "udp-options": null
  }
]
' > ~/workdir/create-httplb1-securitylist-egress.json
```



Security List の作成

```
oci network security-list create --display-name http_securitylist --egress-security-rules file://~/workdir/create-httplb1-securitylist-egress.json --ingress-security-rules file://~/workdir/create-httplb1-securitylist-ingress.json --vcn-id $vcn_ocid
```



作成した security list の OCID を変数に格納します

```
set security_list_ocid (oci network security-list list --vcn-id $vcn_ocid --display-name "http_securitylist" | jq -r '.data[0].id')
```





## Route Tableの作成

作成済みのInternetGatewayのIDを取得します

```
set ig_ocid (oci network internet-gateway list --display-name "tutorial-int-gw1" --vcn-id $vcn_ocid | jq -r '.data[0].id')
```



RuleのJSON作成

```
mkdir ~/workdir
string trim '
[ 
  {
    "cidrBlock":"0.0.0.0/0",
    "destination": "0.0.0.0/0",
    "destination-type": "CIDR_BLOCK",
    "networkEntityId":"sedstring"
  }
]
' > ~/workdir/routetable_rule.json
sed -i "s/sedstring/$ig_ocid/g" ~/workdir/routetable_rule.json
```



確認

```
> cat routetable_rule.json
[
  {
    "cidrBlock":"0.0.0.0/0",
    "destination": "0.0.0.0/0",
    "destination-type": "CIDR_BLOCK",
    "networkEntityId":"ocid1.internetgateway.oc1.iad.aaaaaaaaknm4us55oouldxwrk5oi7hmyjeju6vb5wgrixrk5tk6pp76gnkhq"
  }
]
```



作成

```
oci network route-table create --display-name lb_routetable --vcn-id $vcn_ocid --route-rules file://~/workdir/routetable_rule.json
```



確認

```
> oci network route-table list --vcn-id $vcn_ocid
{
  "data": [
    {
      "compartment-id": "mask",
      "defined-tags": {},
      "display-name": "lb_routetable",
      "freeform-tags": {},
      "id": "ocid1.routetable.oc1.iad.aaaaaaaa7xe6ufwopliid7gqc766gdsd27gdeom6gwooxfek3szsq23tutia",
      "lifecycle-state": "AVAILABLE",
      "route-rules": [
        {
          "cidr-block": "0.0.0.0/0",
          "destination": "0.0.0.0/0",
          "destination-type": "CIDR_BLOCK",
          "network-entity-id": "ocid1.internetgateway.oc1.iad.aaaaaaaaknm4us55oouldxwrk5oi7hmyjeju6vb5wgrixrk5tk6pp76gnkhq"
        }
      ],
      "time-created": "2019-02-09T03:20:25.918000+00:00",
      "vcn-id": "ocid1.vcn.oc1.iad.aaaaaaaamqjvjlxum3t2p727i2akoeltk2z2tk4wxukoqlmbskf27lzollna"
    }
  ]
```



変数に格納します

```
set routetable_ocid (oci network route-table list --vcn-id $vcn_ocid --display-name "lb_routetable" | jq -r '.data[0].id')
```







## LB用のsubnet作成

Instanceと同じサブネットでもOKですが、別のSubnetとして動かしてみます

```
set vcn_ocid (oci network vcn list | jq -r '.data | map(select(.["display-name"] == "TutorialVCN"))[].id')

oci network subnet create --availability-domain AJtg:US-ASHBURN-AD-1 --cidr-block 172.16.11.0/24 --vcn-id $vcn_ocid --display-name lb_subnet1 --dns-label lbsubnet1 --prohibit-public-ip-on-vnic false --route-table-id $routetable_ocid --security-list-ids "[\"$security_list_ocid\"]"

oci network subnet create --availability-domain AJtg:US-ASHBURN-AD-2 --cidr-block 172.16.12.0/24 --vcn-id $vcn_ocid --display-name lb_subnet2 --dns-label lbsubnet2 --prohibit-public-ip-on-vnic false --route-table-id $routetable_ocid --security-list-ids "[\"$security_list_ocid\"]"
```



変数に格納します

```
set lbsubnet1 (oci network subnet list --vcn-id $vcn_ocid --display-name "lb_subnet1" | jq -r '.data[0].id')
set lbsubnet2 (oci network subnet list --vcn-id $vcn_ocid --display-name "lb_subnet2" | jq -r '.data[0].id')
```





## Load Balancer の作成

LoadBalancerの作成

```
oci lb load-balancer create --display-name "httplb1" --shape-name "100Mbps" --is-private false --subnet-ids "[\"$lbsubnet1\",\"$lbsubnet2\"]"
```



LoadBalancerのIDを取得

``` 
set lb_ocid (oci lb load-balancer list --display-name "httplb1" | jq -r '.data[0].id')
```



## backend-setの作成

backendのパラメータを指定するためにJSONファイルを作成。作成した2台のInstanceの情報を指定します。

```
string trim '
[
  {
    "backup": false,
    "drain": false,
    "ip-address": "172.16.2.2",
    "offline": false,
    "port": 80,
    "weight": 1
  },
  {
    "backup": false,
    "drain": false,
    "ip-address": "172.16.3.2",
    "offline": false,
    "port": 80,
    "weight": 1
  }
]
' > ~/workdir/backends.json
```



Backend-set を作成します。Instanceに設定した Apache に沿うようにパラメータを指定します。

```
oci lb backend-set create \
--name "httplb1_backend1" \
--load-balancer-id $lb_ocid \
--backends file://~/workdir/backends.json \
--health-checker-interval-in-ms 100000 \
--health-checker-port 80 \
--health-checker-protocol "HTTP" \
--health-checker-response-body-regex "" \
--health-checker-retries 3 \
--health-checker-return-code 200 \
--health-checker-timeout-in-ms 3000 \
--health-checker-url-path "/" \
--policy "ROUND_ROBIN"
```



確認します

```
> oci lb backend-set list --load-balancer-id $lb_ocid
{
  "data": [
    {
      "backends": [
        {
          "backup": false,
          "drain": false,
          "ip-address": "172.16.2.2",
          "name": "172.16.2.2:80",
          "offline": false,
          "port": 80,
          "weight": 1
        },
        {
          "backup": false,
          "drain": false,
          "ip-address": "172.16.3.2",
          "name": "172.16.3.2:80",
          "offline": false,
          "port": 80,
          "weight": 1
        }
      ],
      "health-checker": {
        "interval-in-millis": 100000,
        "port": 80,
        "protocol": "HTTP",
        "response-body-regex": "",
        "retries": 3,
        "return-code": 200,
        "timeout-in-millis": 3000,
        "url-path": "/"
      },
      "name": "httplb1_backend1",
      "policy": "ROUND_ROBIN",
      "session-persistence-configuration": null,
      "ssl-configuration": null
    }
  ],
  "etag": "142338114"
}
```



## listener の作成

listenerの作成

```
oci lb listener create --default-backend-set-name "httplb1_backend1" --port 80 --protocol "HTTP" --name "httplb1_listener1" --load-balancer-id $lb_ocid
```



# LoadBalancer経由で InstanceにHTTPアクセス(Global IP)

アクセスするたびに、ラウンドロビンでアクセス先が切り替わっていることを確認できます。

```
> curl http://129.213.171.71/
Web Server 1

> curl http://129.213.171.71/
Web Server 2
```



# LoadBalancerをhostname経由でアクセス

OCI DNSで名前解決用のAレコードを作成します。
まずは、JSONのパラメータファイルを生成します。IP Address は LoadBalancer の GlobalIP を指定しています。

```
string trim '
[
  {
    "domain": "test.sugi.tokyo",
    "is-protected": false,
    "rdata": "129.213.171.71",
    "rrset-version": "2",
    "rtype": "A",
    "ttl": 30
  }
]
' > ~/workdir/test.sugi.tokyo.json
```



ZoneにA Record を作成します

```
oci dns record domain patch --zone-name-or-id "sugi.tokyo" --domain "test.sugi.tokyo" --items file://~/workdir/test.sugi.tokyo.json
```



# LoadBalancer経由で InstanceにHTTPアクセス(Hostname)

アクセスするたびに、ラウンドロビンでアクセス先が切り替わっていることを確認できます。

```
> curl http://test.sugi.tokyo/ 
Web Server 1

> curl http://test.sugi.tokyo/ 
Web Server 2
```







# 参考URL

チュートリアル一覧
https://community.oracle.com/docs/DOC-1019313