全部产品
Search
文档中心

Resource Orchestration Service:ALIYUN::SLB::Listener

更新时间:Feb 07, 2026

Anda dapat menggunakan ALIYUN::SLB::Listener untuk membuat listener Server Load Balancer (SLB).

Sintaks

 {
  "Type": "ALIYUN::SLB::Listener",
  "Properties": {
    "MasterSlaveServerGroupId": String,
    "AclStatus": String,
    "Protocol": String,
    "AclId": String,
    "ServerCertificateId": String,
    "HealthCheck": Map,
    "RequestTimeout": Integer,
    "IdleTimeout": Integer,
    "ListenerPort": Integer,
    "HttpConfig": Map,
    "Bandwidth": Integer,
    "AclType": String,
    "BackendServerPort": Integer,
    "Scheduler": String,
    "LoadBalancerId": String,
    "CACertificateId": String,
    "Persistence": Map,
    "VServerGroupId": String,
    "Description": String,
    "PortRange": List,
    "StartListener": Boolean,
    "EnableHttp2": String,
    "Gzip": String,
    "TLSCipherPolicy": String,
    "AclIds": List,
    "ProxyProtocolV2Enabled": Boolean,
    "ConnectionDrainTimeout": Integer,
    "Tags": List,
    "FullNatEnabled": Boolean,
    "ConnectionDrain": String
  }
}

Properti

Nama properti

Tipe

Wajib

Pembaruan diizinkan

Deskripsi

Batasan

MasterSlaveServerGroupId

String

Tidak

Tidak

ID kelompok server utama/cadangan.

Tidak ada

AclStatus

String

Tidak

Ya

Menentukan apakah akan mengaktifkan kontrol akses.

Nilai yang valid:

  • on (default): Mengaktifkan kontrol akses.

  • off: Menonaktifkan kontrol akses.

EnableHttp2

String

Tidak

Ya

Menentukan apakah akan mengaktifkan HTTP/2.

Nilai yang valid:

  • on: Mengaktifkan HTTP/2.

  • off: Menonaktifkan HTTP/2.

AclId

String

Tidak

Ya

ID kelompok kebijakan kontrol akses yang disambungkan ke listener.

Parameter ini wajib ketika AclStatus diatur ke on.

AclType

String

Tidak

Ya

Jenis kebijakan kontrol akses.

Nilai yang valid:

  • white: Meneruskan hanya permintaan dari alamat IP atau blok CIDR yang ditentukan dalam kelompok kebijakan kontrol akses yang dipilih. Daftar putih cocok untuk aplikasi yang hanya mengizinkan akses dari alamat IP tertentu. Penggunaan daftar putih membawa risiko. Jika Anda menetapkan daftar putih, hanya alamat IP dalam daftar putih yang dapat mengakses listener SLB. Jika Anda mengaktifkan daftar putih tetapi tidak menambahkan alamat IP apa pun ke kelompok kebijakan, listener SLB tidak akan meneruskan permintaan apa pun.

  • black: Memblokir semua permintaan dari alamat IP atau blok CIDR yang ditentukan dalam kelompok kebijakan kontrol akses yang dipilih. Blacklist cocok untuk skenario di mana Anda ingin memblokir akses hanya dari alamat IP tertentu. Jika Anda mengaktifkan blacklist tetapi tidak menambahkan alamat IP apa pun ke kelompok kebijakan, listener SLB akan meneruskan semua permintaan. Parameter ini wajib ketika AclStatus diatur ke on.

Protocol

String

Ya

Tidak

Protokol jaringan.

Nilai yang valid:

  • http

  • https

  • tcp

  • udp

ListenerPort

Integer

Ya

Tidak

Port frontend yang digunakan oleh instans SLB.

Rentang nilai: 1 hingga 65.535.

Bandwidth

Integer

Ya

Ya

Bandwidth puncak listener.

Rentang nilai: -1 atau 1 hingga 1.000.

Unit: Mbps.

Catatan:

  • Untuk instans yang menghadap publik dengan metode penagihan pay-by-bandwidth, jumlah nilai bandwidth puncak semua listener tidak boleh melebihi nilai bandwidth yang ditentukan saat Anda membuat instans SLB. Anda tidak dapat mengatur bandwidth listener ke -1.

  • Untuk instans yang menghadap publik dengan metode penagihan pay-by-traffic, Anda dapat mengatur bandwidth listener ke -1. Nilai ini menunjukkan bahwa bandwidth tidak dibatasi.

BackendServerPort

Integer

Tidak

Tidak

Port backend yang digunakan oleh instans SLB.

Rentang nilai: 1 hingga 65.535.

FullNatEnabled

Boolean

Tidak

Ya

Ketika mode full-NAT diaktifkan, server backend dapat bertindak sebagai klien untuk mengakses sumber daya eksternal.

Nilai default: false.

Catatan: Parameter ini hanya berlaku untuk listener TCP dan UDP.

LoadBalancerId

String

Ya

Tidak

ID instans SLB.

Tidak ada

HealthCheck

Map

Tidak

Ya

Pengaturan pemeriksaan kesehatan.

Untuk informasi selengkapnya, lihat properti HealthCheck.

Persistence

Map

Tidak

Ya

Mempertahankan parameter terkait.

Untuk informasi selengkapnya, lihat properti Persistence.

Scheduler

String

Tidak

Tidak

Algoritma penjadwalan.

Nilai yang valid:

  • wrr (default): Server backend dengan bobot lebih tinggi menerima lebih banyak permintaan.

  • wlc: Permintaan didistribusikan ke server backend secara berurutan.

CACertificateId

String

Tidak

Tidak

ID Sertifikat CA.

Parameter ini hanya berlaku untuk protokol HTTPS.

ServerCertificateId

String

Tidak

Ya

ID Sertifikat server.

Parameter ini wajib dan hanya berlaku untuk protokol HTTPS.

VServerGroupId

String

Tidak

Ya

ID kelompok server.

Tidak ada

RequestTimeout

Integer

Tidak

Tidak

Periode timeout permintaan.

Rentang nilai: 1 hingga 180.

Unit: detik.

IdleTimeout

Integer

Tidak

Tidak

Periode timeout koneksi idle.

Rentang nilai: 1 hingga 60.

Unit: detik.

HttpConfig

Map

Tidak

Tidak

Digunakan untuk mengonfigurasi protokol HTTP.

Untuk informasi selengkapnya, lihat properti HttpConfig.

Description

String

Tidak

Tidak

Deskripsi listener.

Panjang harus 1 hingga 80 karakter. Dapat berisi huruf, angka, tanda hubung (-), garis miring (/), titik (.), dan garis bawah (_).

PortRange

List

Tidak

Tidak

Range port pendengaran.

Saat ini, hanya mendengarkan pada semua port yang didukung. Artinya StartPort harus 1 dan EndPort harus 65.535.

Untuk informasi selengkapnya, lihat properti PortRange.

StartListener

Boolean

Tidak

Tidak

Menentukan apakah akan memulai listener.

Nilai yang valid:

  • true (default): Memulai listener.

  • false: Tidak memulai listener.

Gzip

String

Tidak

Ya

Menentukan apakah akan mengaktifkan kompresi Gzip untuk mengompres jenis file tertentu.

Nilai yang valid:

  • true (default): Diaktifkan.

  • False: Proses tidak dimulai.

TLSCipherPolicy

String

Tidak

Ya

Kebijakan keamanan TLS.

Setiap kebijakan keamanan berisi versi TLS dan paket sandi yang dapat digunakan untuk HTTPS.

Catatan

Parameter ini berlaku ketika Protocol diatur ke https.

AclIds

List

Tidak

Ya

Daftar ID kebijakan kontrol akses yang akan dikaitkan dengan listener.

Parameter ini wajib jika parameter AclStatus diatur ke on. AclIds memiliki prioritas lebih tinggi daripada AclId.

ProxyProtocolV2Enabled

Boolean

Tidak

Ya

Menentukan apakah akan menggunakan Proxy Protocol untuk meneruskan alamat IP sumber klien ke server backend.

Nilai yang valid:

  • true: Ya.

  • false: Tidak.

ConnectionDrainTimeout

Integer

Tidak

Ya

Periode timeout untuk pengurasan koneksi.

Unit: detik.

Rentang nilai: 10 hingga 900.

Tags

List

Tidak

Ya

Daftar tag.

Untuk informasi selengkapnya, lihat properti Tags.

ConnectionDrain

String

Tidak

Ya

Menentukan apakah akan mengaktifkan pengurasan koneksi.

Nilai yang valid:

  • on: Ya.

  • off: Tidak.

Sintaks HealthCheck

"HealthCheck": {
  "Domain": String,
  "Interval": Integer,
  "URI": String,
  "HttpCode": String,
  "HealthyThreshold": Integer,
  "HealthCheckType": String,
  "Timeout": Integer,
  "UnhealthyThreshold": Integer,
  "Port": Integer,
  "Switch": String,
  "HealthCheckMethod": String,
  "Req": String,
  "Exp": String
}

Properti HealthCheck

Nama properti

Type

Wajib

Pembaruan diizinkan

Deskripsi

Batasan

Domain

String

Tidak

Tidak

Nama domain yang digunakan untuk pemeriksaan kesehatan.

Nilai yang valid:

  • $_ip

  • String kustom dengan panjang 1 hingga 80 karakter. Dapat berisi huruf, angka, tanda hubung (-), dan titik (.).

  • kosong

Catatan

Jika Anda mengatur parameter ini ke $_ip atau membiarkannya kosong, SLB menggunakan alamat IP pribadi setiap server backend sebagai nama domain untuk pemeriksaan kesehatan.

Interval

Integer

Tidak

Tidak

Interval antara pemeriksaan kesehatan.

Rentang nilai: 1 hingga 5.

Unit: detik.

URI

String

Tidak

Tidak

URI yang digunakan untuk pemeriksaan kesehatan.

Nilai harus terdiri dari 1 hingga 80 karakter. Harus diawali dengan garis miring (/). Dapat berisi huruf, angka, tanda hubung (-), garis miring (/), titik (.), tanda persen (%), tanda tanya (?), tanda pagar (#), dan tanda ampersand (&).

HttpCode

String

Tidak

Tidak

Kode status HTTP.

Nilai yang valid:

  • http_2xx (default)

  • http_3xx

  • http_4xx

  • http_5xx

Pisahkan beberapa kode status HTTP dengan koma (,).

HealthyThreshold

Integer

Tidak

Tidak

Jumlah pemeriksaan kesehatan berturut-turut yang berhasil sebelum server backend dinyatakan sehat. Setelah server backend dinyatakan tidak sehat, server tersebut harus lulus jumlah pemeriksaan kesehatan berturut-turut ini untuk dinyatakan sehat kembali.

Rentang nilai: 1 hingga 10.

HealthCheckType

String

Tidak

Tidak

Jenis pemeriksaan kesehatan.

Nilai yang valid:

  • tcp

  • http

Timeout

Integer

Tidak

Tidak

Periode timeout maksimum untuk respons pemeriksaan kesehatan.

Rentang nilai: 1 hingga 50.

Unit: detik.

Catatan

Jika nilai Timeout kurang dari nilai Interval, nilai Timeout diabaikan dan nilai Interval digunakan sebagai periode timeout.

UnhealthyThreshold

Integer

Tidak

Tidak

Jumlah pemeriksaan kesehatan berturut-turut yang gagal sebelum server backend dinyatakan tidak sehat. Setelah server backend dinyatakan sehat, server tersebut harus gagal dalam jumlah pemeriksaan kesehatan berturut-turut ini untuk dinyatakan tidak sehat.

Rentang nilai: 1 hingga 10.

Port

Integer

Tidak

Tidak

Port yang digunakan untuk pemeriksaan kesehatan.

Rentang nilai: 0 hingga 65.535.

Switch

String

Tidak

Tidak

Menentukan apakah akan mengaktifkan pemeriksaan kesehatan.

Nilai yang valid:

  • on: Mengaktifkan pemeriksaan kesehatan.

  • off: Menonaktifkan pemeriksaan kesehatan.

Catatan

Parameter ini saat ini hanya berlaku untuk protokol HTTP atau HTTPS. Jika Anda tidak mengatur Switch, pemeriksaan kesehatan dinonaktifkan secara default, kecuali jika Anda telah mengonfigurasi item pemeriksaan kesehatan.

HealthCheckMethod

String

Tidak

Tidak

Metode pemeriksaan kesehatan.

Nilai yang valid:

  • head

  • get

Catatan

Parameter ini berlaku ketika Protocol diatur ke https atau http, dan Switch diatur ke on.

Req

String

Tidak

Tidak

String permintaan untuk pemeriksaan kesehatan listener UDP. String hanya dapat berisi huruf dan angka.

Panjang maksimum adalah 64 karakter.

Exp

String

Tidak

Tidak

String respons untuk pemeriksaan kesehatan listener UDP. String hanya dapat berisi huruf dan angka.

Panjang maksimum adalah 64 karakter.

Sintaks Persistence

"Persistence": {
  "PersistenceTimeout": Integer,
  "CookieTimeout": Integer,
  "XForwardedFor": String,
  "XForwardedFor_SLBID": String,
  "XForwardedFor_proto": String,
  "XForwardedFor_SLBIP": String,
  "Cookie": String,
  "StickySession": String,
  "StickySessionType": String,
  "XForwardedFor_ClientSrcPort": String,
  "XForwardedFor_SLBPORT": String
}

Properti Persistence

Nama Properti

Tipe

Wajib

Pembaruan diizinkan

Deskripsi

Batasan

StickySession

String

Tidak

Ya

Menentukan apakah akan mengaktifkan persistensi sesi.

Nilai yang valid:

  • on: Mengaktifkan persistensi sesi.

  • off: Menonaktifkan persistensi sesi.

    Catatan

    Parameter ini hanya berlaku untuk protokol HTTP dan HTTPS.

PersistenceTimeout

Integer

Tidak

Ya

Periode timeout untuk persistensi koneksi.

Rentang nilai: 0 hingga 1.000.

Nilai default: 0 (menunjukkan dinonaktifkan).

Unit: detik.

CookieTimeout

Integer

Tidak

Ya

Periode timeout cookie.

Rentang nilai: 1 hingga 86.400.

Unit: detik.

Catatan

Parameter ini wajib ketika StickySession diatur ke on dan StickySessionType diatur ke insert.

XForwardedFor

String

Tidak

Ya

Menentukan apakah akan menggunakan header X-Forwarded-For untuk mengambil alamat IP asal klien.

Nilai yang valid:

  • on: Menggunakan header X-Forwarded-For untuk mengambil alamat IP asal klien.

  • off (default): Tidak menggunakan header X-Forwarded-For untuk mengambil alamat IP asal klien.

XForwardedFor_proto

String

Tidak

Ya

Menentukan apakah akan menggunakan header X-Forwarded-Proto untuk mengambil protokol listener instans SLB.

Nilai yang valid:

  • on: Menggunakan header X-Forwarded-Proto untuk mengambil protokol listener instans SLB.

  • off (default): Tidak menggunakan header X-Forwarded-Proto untuk mengambil protokol listener instans SLB.

XForwardedFor_SLBID

String

Tidak

Ya

Menentukan apakah akan menggunakan header SLB-ID untuk mengambil ID instans SLB.

Nilai yang valid:

  • on: Menggunakan header SLB-ID untuk mengambil ID instans SLB.

  • off (default): Tidak menggunakan header SLB-ID untuk mengambil ID instans SLB.

XForwardedFor_SLBIP

String

Tidak

Ya

Apakah alamat IP asal permintaan klien diambil dari field header SLB-IP.

Nilai yang valid:

  • On: Mendapatkan alamat IP asal permintaan klien dari field header SLB-IP.

  • off (default): Alamat IP asal klien tidak diambil dari field header SLB-IP.

Cookie

String

Tidak

Ya

Cookie yang dikonfigurasi di server.

Nilai harus terdiri dari 1 hingga 200 karakter dan tidak boleh diawali dengan tanda dolar ($). Dapat berisi huruf dan angka, tetapi tidak boleh berisi koma (,), titik koma (;), atau spasi.

Catatan

Parameter ini wajib ketika StickySession diatur ke on dan StickySessionType diatur ke server.

StickySessionType

String

Tidak

Ya

Metode yang digunakan untuk menangani cookie.

Nilai yang valid:

  • insert: Menyisipkan cookie.

  • server: Menulis ulang cookie.

Catatan

Parameter ini wajib ketika StickySession diatur ke on.

XForwardedFor_ClientSrcPort

String

Tidak

Ya

Menentukan apakah akan menggunakan header X-Forwarded-Client-srcport untuk mengambil port yang digunakan klien untuk terhubung ke instans SLB.

Nilai yang valid:

  • on: Menggunakan header X-Forwarded-Client-srcport untuk mengambil port yang digunakan klien untuk terhubung ke instans SLB.

  • off (default): Tidak menggunakan header X-Forwarded-Client-srcport untuk mengambil port yang digunakan klien untuk terhubung ke instans SLB.

XForwardedFor_SLBPORT

String

Tidak

Ya

Menentukan apakah akan menggunakan header X-Forwarded-Port untuk mengambil port pendengaran instans SLB.

Nilai yang valid:

  • On: Mengambil protokol listener yang digunakan oleh instans SLB dari field header X-Forwarded-Port.

  • off (default): Tidak menggunakan header X-Forwarded-Port untuk mengambil port pendengaran instans SLB.

Sintaks HttpConfig

"HttpConfig": {
  "ForwardPort": Integer,
  "ListenerForward": String
}

Properti HttpConfig

Nama properti

Jenis

Wajib

Pembaruan diizinkan

Deskripsi

Batasan

ForwardPort

Integer

Tidak

Tidak

Port tempat permintaan HTTP diteruskan untuk listener HTTPS.

Rentang nilai: 1 hingga 65.535.

Nilai default: 443.

ListenerForward

String

Tidak

Tidak

Menentukan apakah akan mengaktifkan penerusan HTTP ke HTTPS.

Nilai yang valid:

  • Diaktifkan.

  • off (default): dinonaktifkan.

Sintaks PortRange

"PortRange": [
  {
    "StartPort": Integer,
    "EndPort": Integer
  }
]

Properti PortRange

Nama Properti

Type

Wajib

Pembaruan diizinkan

Deskripsi

Batasan

StartPort

Integer

Ya

Tidak

Port awal.

Nilai: 1.

EndPort

Integer

Ya

Tidak

Port akhir.

Nilai: 65.535.

Sintaks Tags

"Tags": [
  {
    "Key": String,
    "Value": String
  }
]

Properti Tags

Properti

Tipe

Wajib

Pembaruan diizinkan

Deskripsi

Batasan

Key

String

Ya

Tidak

Kunci tag.

Tidak ada

Value

String

Tidak

Tidak

Nilai tag.

Tidak ada

Nilai yang dikembalikan

Fn::GetAtt

  • LoadBalancerId: ID unik instans SLB.

  • ListenerPortsAndProtocol: Port frontend dan protokol yang digunakan oleh instans SLB.

  • Arn: Nama Sumber Daya Alibaba Cloud (ARN).

Contoh

Skenario 1: Membuat listener SLB

Buat cepat

ROSTemplateFormatVersion: '2015-09-01'
Description: Test SLB Listener
Parameters:
  SlbInstanceId:
    AssociationProperty: ALIYUN::SLB::Instance::InstanceId
    Type: String
Resources:
  Listener:
    Type: ALIYUN::SLB::Listener
    Properties:
      BackendServerPort: 8080
      Bandwidth: 50
      ListenerPort: 80
      LoadBalancerId:
        Ref: SlbInstanceId
      Protocol: https
      Scheduler: wrr
Outputs: {}
{
  "ROSTemplateFormatVersion": "2015-09-01",
  "Description": "Test SLB Listener",
  "Parameters": {
    "SlbInstanceId": {
      "AssociationProperty": "ALIYUN::SLB::Instance::InstanceId",
      "Type": "String"
    }
  },
  "Resources": {
    "Listener": {
      "Type": "ALIYUN::SLB::Listener",
      "Properties": {
        "BackendServerPort": 8080,
        "Bandwidth": 50,
        "ListenerPort": 80,
        "LoadBalancerId": {
          "Ref": "SlbInstanceId"
        },
        "Protocol": "https",
        "Scheduler": "wrr"
      }
    }
  },
  "Outputs": {
  }
}

Skenario 2: Membuat listener SLB dengan pemeriksaan kesehatan

Buat cepat

ROSTemplateFormatVersion: '2015-09-01'
Description: Test SLB Listener
Parameters:
  SlbInstanceId:
    AssociationProperty: ALIYUN::SLB::Instance::InstanceId
    Type: String
Resources:
  Listener:
    Type: ALIYUN::SLB::Listener
    Properties:
      ListenerPort: 80
      Bandwidth: 10
      HealthCheck:
        HttpCode: http_2xx,http_3xx,http_4xx,http_5xx
        HealthCheckType: http
        UnhealthyThreshold: 3
        Timeout: 5
        HealthyThreshold: 3
        Port: 80
        URI: /
        Interval: 5
      LoadBalancerId:
        Ref: SlbInstanceId
      BackendServerPort: 80
      Protocol: http
Outputs: {}
{
  "ROSTemplateFormatVersion": "2015-09-01",
  "Description": "Test SLB Listener",
  "Parameters": {
    "SlbInstanceId": {
      "AssociationProperty": "ALIYUN::SLB::Instance::InstanceId",
      "Type": "String"
    }
  },
  "Resources": {
    "Listener": {
      "Type": "ALIYUN::SLB::Listener",
      "Properties": {
        "BackendServerPort": 8080,
        "Bandwidth": 50,
        "ListenerPort": 80,
        "LoadBalancerId": {
          "Ref": "SlbInstanceId"
        },
        "Protocol": "https",
        "Scheduler": "wrr"
      }
    }
  },
  "Outputs": {
  }
}

Skenario 3: Membuat layanan web dengan ketersediaan tinggi

Buat cepat

ROSTemplateFormatVersion: '2015-09-01'
Description:
  zh-cn: Build a high-availability web service that includes dual-zone ECS instances, an SLB instance, and NAS mounts. The service supports automatic configuration synchronization and public network access.
  en: Membangun layanan web ketersediaan tinggi terdiri dari instans ECS zona ketersediaan ganda, Load Balancer (SLB), pemasangan Storage Terlampir Jaringan (NAS), sinkronisasi konfigurasi otomatis, dan dapat diakses melalui internet publik.
Parameters:
  NasZone1:
    AssociationProperty: 'ALIYUN::ECS::Instance::ZoneId'
    Type: String
    Description:
      zh-cn: Zone 1 must be different from Zone 2.
      en: Zona ketersediaan 1 harus berbeda dari zona ketersediaan 2.
    Label:
      zh-cn: NAS Zone 1
      en: Zona Ketersediaan NAS1
  NasZone2:
    AssociationProperty: 'ALIYUN::ECS::Instance::ZoneId'
    Type: String
    Description:
      zh-cn: Zone 2 must be different from Zone 1.
      en: Zona ketersediaan 2 harus berbeda dari zona ketersediaan 1.
    Label:
      zh-cn: NAS Zone 2
      en: Zona Ketersediaan NAS2
  CommonName:
    Default: high-availability
    Type: String
  InstancePassword:
    Type: String
    Description:
      zh-cn: >-
        The logon password of the server. The password must be 8 to 30 characters in length and contain at least three of the following character types: uppercase letters, lowercase letters, digits, and special characters. Special characters include ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/
      en: >-
        Kata sandi logon server, Panjang 8~30, harus berisi tiga (huruf kapital,
        huruf kecil, angka, ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ simbol khusus).
    MinLength: 8
    Label:
      zh-cn: Instance Password
      en: Kata Sandi Instans
    AllowedPattern: '[0-9A-Za-z\_\-\&:;''<>,=%`~!@#\(\)\$\^\*\+\|\{\}\[\]\.\?\/]+$'
    NoEcho: true
    MaxLength: 30
    AssociationProperty: 'ALIYUN::ECS::Instance::Password'
    ConstraintDescription:
      zh-cn: 'The password must be 8 to 30 characters in length and contain at least three of the following character types: uppercase letters, lowercase letters, digits, and special characters. Special characters include ()`~!@#$%^&*_-+=|{}[]:;''<>,.?/'
      en: >-
        Panjang 8~30, harus berisi tiga (huruf kapital, huruf kecil,
        angka, ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ simbol khusus).
  EcsInstanceType2:
    AssociationProperty: 'ALIYUN::ECS::Instance::InstanceType'
    AssociationPropertyMetadata:
      SystemDiskCategory: cloud_essd
      InstanceChargeType: PostPaid
      ZoneId: '${Zone2}'
    Type: String
    Label:
      zh-cn: Instance Type of Zone 2
      en: Tipe Instans Zona Ketersediaan2
  Zone2:
    AssociationProperty: 'ALIYUN::ECS::Instance::ZoneId'
    Type: String
    Description:
      zh-cn: Zone 2 must be different from Zone 1.
      en: Zona ketersediaan 2 harus berbeda dari zona ketersediaan 1.
    Label:
      zh-cn: vSwitch Zone 2
      en: Zona Ketersediaan VSwitch2
  Zone1:
    AssociationProperty: 'ALIYUN::ECS::Instance::ZoneId'
    Type: String
    Description:
      zh-cn: Zone 1 must be different from Zone 2.
      en: Zona ketersediaan 1 harus berbeda dari zona ketersediaan 2.
    Label:
      zh-cn: vSwitch Zone 1
      en: Zona Ketersediaan VSwitch1
  EcsInstanceType1:
    AssociationProperty: 'ALIYUN::ECS::Instance::InstanceType'
    AssociationPropertyMetadata:
      SystemDiskCategory: cloud_essd
      InstanceChargeType: PostPaid
      ZoneId: '${Zone1}'
    Type: String
    Label:
      zh-cn: Instance Type of Zone 1
      en: Tipe Instans Zona Ketersediaan1
Rules:
  DifferentZones2:
    Assertions:
      - Assert:
          'Fn::Not':
            'Fn::Equals':
              - Ref: NasZone1
              - Ref: NasZone2
        AssertDescription: Zona NAS harus berbeda
  DifferentZones1:
    Assertions:
      - Assert:
          'Fn::Not':
            'Fn::Equals':
              - Ref: Zone1
              - Ref: Zone2
        AssertDescription: Zona ECS harus berbeda
Outputs:
  ECS1URL:
    Description: URL ECS 1
    Value:
      'Fn::Sub':
        - >-
          https://ecs.console.alibabacloud.com/#/server/region/${region}?instanceIds=${InstanceID}
        - InstanceID:
            'Fn::Select':
              - '0'
              - 'Fn::GetAtt':
                  - EcsInstanceGroup1
                  - InstanceIds
          region:
            Ref: 'ALIYUN::Region'
  FileSystemId1:
    Description:
      zh-cn: Master NAS
      en: NAS Utama
    Value:
      'Fn::Sub':
        - 'https://nas.console.alibabacloud.com/${region}/filesystem/${InstanceID}'
        - InstanceID:
            'Fn::GetAtt':
              - MasterFileSystem
              - FileSystemId
          region:
            Ref: 'ALIYUN::Region'
  ECS2URL:
    Description: URL ECS 2
    Value:
      'Fn::Sub':
        - >-
          https://ecs.console.alibabacloud.com/#/server/region/${region}?instanceIds=${InstanceID}
        - InstanceID:
            'Fn::Select':
              - '0'
              - 'Fn::GetAtt':
                  - EcsInstanceGroup1
                  - InstanceIds
          region:
            Ref: 'ALIYUN::Region'
  SlbIpAddress:
    Description:
      zh-cn: The public IP address exposed to the Internet.
      en: Alamat IP Publik
    Value:
      'Fn::Sub':
        - 'http://${ServerAddress}'
        - ServerAddress:
            'Fn::GetAtt':
              - Slb
              - IpAddress
  FileSystemId2:
    Description:
      zh-cn: Secondary NAS
      en: NAS Cadangan
    Value:
      'Fn::Sub':
        - 'https://nas.console.alibabacloud.com/${region}/filesystem/${InstanceID}'
        - InstanceID:
            'Fn::GetAtt':
              - BackupFileSystem
              - FileSystemId
          region:
            Ref: 'ALIYUN::Region'
  MountInfo1:
    Description:
      zh-cn: NAS mount directory 1 on the ECS instance
      en: Direktori pemasangan NAS 1 pada ECS
    Value: '/nas_master'
  MountInfo2:
    Description:
      zh-cn: NAS mount directory 2 on the ECS instance
      en: Direktori pemasangan NAS 2 pada ECS
    Value: '/nas_backup'
Resources:
  SlbListener:
    Type: 'ALIYUN::SLB::Listener'
    Properties:
      Protocol: http
      HealthCheck:
        HealthCheckType: http
        Interval: 2
        URI: /
        UnhealthyThreshold: 3
        HealthyThreshold: 3
        Timeout: 5
        HttpCode: 'http_2xx,http_3xx,http_4xx,http_5xx'
        Port: 80
      ListenerPort: 80
      Bandwidth: 10
      BackendServerPort: 80
      LoadBalancerId:
        Ref: Slb
    DependsOn:
      - Slb
  EcsSecurityGroup:
    Type: 'ALIYUN::ECS::SecurityGroup'
    Properties:
      SecurityGroupIngress:
        - Priority: 1
          PortRange: 80/80
          NicType: internet
          SourceCidrIp: 0.0.0.0/0
          IpProtocol: tcp
      VpcId:
        Ref: EcsVpc
      SecurityGroupEgress:
        - Priority: 1
          PortRange: '-1/-1'
          DestCidrIp: 0.0.0.0/0
          NicType: internet
          IpProtocol: all
        - Priority: 1
          PortRange: '-1/-1'
          DestCidrIp: 0.0.0.0/0
          NicType: intranet
          IpProtocol: all
      SecurityGroupName:
        'Fn::Sub': '${CommonName}_sg'
  MasterNasMountTarget:
    Type: 'ALIYUN::NAS::MountTarget'
    Properties:
      NetworkType: Vpc
      FileSystemId:
        Ref: MasterFileSystem
      VpcId:
        Ref: EcsVpc
      VSwitchId:
        Ref: EcsVSwitch3
      AccessGroupName: DEFAULT_VPC_GROUP_NAME
  EcsVSwitch4:
    Type: 'ALIYUN::ECS::VSwitch'
    Properties:
      VSwitchName:
        'Fn::Sub': '${CommonName}_vsw_002'
      VpcId:
        Ref: EcsVpc
      CidrBlock: 192.168.4.0/24
      ZoneId:
        Ref: NasZone2
  MasterFileSystem:
    Type: 'ALIYUN::NAS::FileSystem'
    Properties:
      StorageType: Capacity
      ProtocolType: NFS
      VpcId:
        Ref: EcsVpc
      Description: MasterNAS
      ZoneId:
        Ref: NasZone1
  EcsVSwitch2:
    Type: 'ALIYUN::ECS::VSwitch'
    Properties:
      VSwitchName:
        'Fn::Sub': '${CommonName}_vsw_002'
      VpcId:
        Ref: EcsVpc
      CidrBlock: 192.168.2.0/24
      ZoneId:
        Ref: Zone2
  EcsVSwitch3:
    Type: 'ALIYUN::ECS::VSwitch'
    Properties:
      VSwitchName:
        'Fn::Sub': '${CommonName}_vsw_002'
      VpcId:
        Ref: EcsVpc
      CidrBlock: 192.168.3.0/24
      ZoneId:
        Ref: NasZone1
  EcsVSwitch1:
    Type: 'ALIYUN::ECS::VSwitch'
    Properties:
      VSwitchName:
        'Fn::Sub': '${CommonName}_vsw_001'
      VpcId:
        Ref: EcsVpc
      CidrBlock: 192.168.1.0/24
      ZoneId:
        Ref: Zone1
  BackupFileSystem:
    Type: 'ALIYUN::NAS::FileSystem'
    Properties:
      StorageType: Capacity
      ProtocolType: NFS
      VpcId:
        Ref: EcsVpc
      Description: BackupNAS
      ZoneId:
        Ref: NasZone2
  BackupNasMountTarget:
    Type: 'ALIYUN::NAS::MountTarget'
    Properties:
      NetworkType: Vpc
      FileSystemId:
        Ref: BackupFileSystem
      VpcId:
        Ref: EcsVpc
      VSwitchId:
        Ref: EcsVSwitch4
      AccessGroupName: DEFAULT_VPC_GROUP_NAME
  EcsInstanceGroup1:
    Type: 'ALIYUN::ECS::InstanceGroup'
    Properties:
      SystemDiskCategory: cloud_essd
      VpcId:
        Ref: EcsVpc
      SecurityGroupId:
        Ref: EcsSecurityGroup
      SystemDiskSize: 40
      ImageId: aliyun_3_x64_20G_alibase_20230727.vhd
      SpotStrategy: SpotAsPriceGo
      IoOptimized: optimized
      VSwitchId:
        Ref: EcsVSwitch1
      Password:
        Ref: InstancePassword
      InstanceName:
        'Fn::Sub': '${CommonName}_ecs_001'
      InstanceType:
        Ref: EcsInstanceType1
      ZoneId:
        Ref: Zone1
      MaxAmount: 1
  EcsInstanceGroup2:
    Type: 'ALIYUN::ECS::InstanceGroup'
    Properties:
      SystemDiskCategory: cloud_essd
      VpcId:
        Ref: EcsVpc
      SecurityGroupId:
        Ref: EcsSecurityGroup
      SystemDiskSize: 40
      ImageId: aliyun_3_x64_20G_alibase_20230727.vhd
      SpotStrategy: SpotAsPriceGo
      IoOptimized: optimized
      VSwitchId:
        Ref: EcsVSwitch2
      Password:
        Ref: InstancePassword
      InstanceName:
        'Fn::Sub': '${CommonName}_ecs_002'
      InstanceType:
        Ref: EcsInstanceType2
      ZoneId:
        Ref: Zone2
      MaxAmount: 1
  EcsVpc:
    Type: 'ALIYUN::ECS::VPC'
    Properties:
      VpcName:
        'Fn::Sub': '${CommonName}_vpc'
      CidrBlock: 192.168.0.0/16
  SlbBackendServerAttachment:
    Type: 'ALIYUN::SLB::BackendServerAttachment'
    Properties:
      BackendServerList:
        'Fn::ListMerge':
          - 'Fn::GetAtt':
              - EcsInstanceGroup1
              - InstanceIds
          - 'Fn::GetAtt':
              - EcsInstanceGroup2
              - InstanceIds
      BackendServerWeightList:
        - 100
        - 100
      LoadBalancerId:
        Ref: Slb
  Slb:
    Type: 'ALIYUN::SLB::LoadBalancer'
    Properties:
      AddressType: internet
      LoadBalancerName:
        'Fn::Sub': '${CommonName}-slb'
      InstanceChargeType: PayByCLCU
      PayType: PayOnDemand
  InstanceRunCommand:
    Type: 'ALIYUN::ECS::RunCommand'
    Properties:
      CommandContent:
        'Fn::Sub': >-
          #!/bin/bash

          if [ ! -f .ros.provision ]; then
            echo "Nama: Layanan web ketersediaan tinggi dengan penyimpanan bersama" > .ros.provision
          fi


          name=$(grep "^Nama:" .ros.provision | awk -F':' '{print $2}' | sed -e
          's/^[[:space:]]*//' -e 's/[[:space:]]*$//')

          if [[ "$name" != "High-availability web service with shared storage" ]]; then
            echo "Instans ini telah dikonfigurasi menggunakan penerapan sekali klik dari tutorial \"$name\". Anda tidak dapat menggunakan penerapan sekali klik dari tutorial ini."
            exit 0
          fi


          echo "#########################"

          echo "# Periksa Jaringan"

          echo "#########################"

          ping -c 2 -W 2 aliyun.com > /dev/null

          if [[ $? -ne 0 ]]; then
            echo "Instans saat ini tidak dapat mengakses jaringan publik."
            exit 0
          fi


          if ! grep -q "^Step1: Prepare Environment$" .ros.provision; then
            echo "#########################"
            echo "# Siapkan Lingkungan"
            echo "#########################"
            systemctl status firewalld
            systemctl stop firewalld
            echo "Step1: Prepare Environment" >> .ros.provision
          else
            echo "#########################"
            echo "# Lingkungan telah siap"
            echo "#########################"
          fi


          if ! grep -q "^Step2: Install Nginx and deploy service$"
          .ros.provision; then
            echo "#########################"
            echo "# Instal Nginx"
            echo "#########################"
            sudo yum -y install nginx
            sudo wget -O /usr/share/nginx/html/index.html https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20231013/jhgg/index.html
            sudo wget -O /usr/share/nginx/html/lipstick.png https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20230925/zevs/lipstick.png
            sudo systemctl start nginx
            sudo systemctl enable nginx
            echo "Step2: Install Nginx and deploy service" >> .ros.provision
          else
            echo "#########################"
            echo "# Nginx telah diinstal"
            echo "#########################"
          fi


          if ! grep -q "^Step3: Mount to the ECS" .ros.provision; then
            echo "#########################"
            echo "# Pasang ke ECS"
            echo "#########################"
            mkdir /nas_master
            mkdir /nas_backup
            sudo yum install -y nfs-utils
            sudo echo "options sunrpc tcp_slot_table_entries=128" >>  /etc/modprobe.d/sunrpc.conf
            sudo echo "options sunrpc tcp_max_slot_table_entries=128" >>  /etc/modprobe.d/sunrpc.conf
            sudo mount -t nfs -o vers=3,nolock,proto=tcp,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport ${MasterNasMountTarget.MountTargetDomain}:/ /nas_master
            sudo mount -t nfs -o vers=3,nolock,proto=tcp,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport ${BackupNasMountTarget.MountTargetDomain}:/ /nas_backup
          
            sudo echo "${MasterNasMountTarget.MountTargetDomain}:/ /nas_master nfs vers=3,nolock,proto=tcp,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,_netdev,noresvport 0 0" >> /etc/fstab
            
            sudo echo "${BackupNasMountTarget.MountTargetDomain}:/ /nas_backup nfs vers=3,nolock,proto=tcp,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,_netdev,noresvport 0 0" >> /etc/fstab

            df -h | grep aliyun
          else
            echo "#########################"
            echo "# ECS telah disambungkan ke NAS"
            echo "#########################"
          fi


          if ! grep -q "^Step4: Shared file$" .ros.provision; then
            echo "#########################"
            echo "# Berkas Bersama"
            echo "#########################"
            sudo cp -Lvr /usr/share/nginx/html /nas_master
            sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
            echo "Step4: Shared file" >> .ros.provision
          else
            echo "#########################"
            echo "# Berkas telah Dibagikan"
            echo "#########################"
          fi


          if ! grep -q "^Step5: Install inotify-tools、rsync$" .ros.provision;
          then
            echo "#########################"
            echo "# Instal inotify-tools, rsync"
            echo "#########################"
            sudo yum install -y inotify-tools rsync
            echo "Step6: Install inotify-tools, rsync" >> .ros.provision
          else
            echo "#########################"
            echo "# Inotify-tools telah diinstal"
            echo "#########################"
          fi

          if ! grep -q "^Step6: Install synchronization server$" .ros.provision;
          then
            echo "#########################"
            echo "# Instal server sinkronisasi"
            echo "#########################"
            sudo wget -P /etc/systemd/system/ https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20231017/pftz/sync_nas.sh
            sudo wget -P /etc/systemd/system/ https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/en-US/20230925/wmaj/sync_check_switch.sh
            sudo chmod +x /etc/systemd/system/sync_nas.sh
            sudo chmod +x /etc/systemd/system/sync_check_switch.sh
            cat > /etc/systemd/system/sync-check-switch.service << \EOF
          [Unit]

          Description=Sinkronisasi Periksa Sakelar

          After=network.target


          [Service]

          ExecStart=/etc/systemd/system/sync_check_switch.sh

          RestartSec=3

          Restart=always


          [Install]

          WantedBy=default.target

          EOF

            cat > /etc/systemd/system/sync-nas.service << \EOF
          [Unit]

          Description=Layanan NAS Sinkronisasi

          After=network.target


          [Service]

          ExecStart=/etc/systemd/system/sync_nas.sh

          Restart=always

          RestartSec=3


          [Install]

          WantedBy=default.target

          EOF

            sudo systemctl daemon-reload
            sudo systemctl start sync-nas.service
            sudo systemctl enable sync-check-switch.service
            sudo systemctl start sync-check-switch.service
            sudo systemctl enable sync-nas.service
            echo "Step6: Install " >> .ros.provision
          else
            echo "#########################"
            echo "# Server sinkronisasi telah diinstal"
            echo "#########################"
          fi
      Type: RunShellScript
      Sync: true
      InstanceIds:
        - Ref: EcsInstanceGroup1
        - Ref: EcsInstanceGroup2
      Timeout: '300'
Metadata:
  'ALIYUN::ROS::Interface':
    ParameterGroups:
      - Parameters:
          - Zone1
          - Zone2
          - NasZone1
          - NasZone2
        Label:
          default:
            zh-cn: Zone Configuration
            en: Konfigurasi Zona
      - Parameters:
          - EcsInstanceType1
          - EcsInstanceType2
          - InstancePassword
        Label:
          default:
            zh-cn: ECS Instance Configuration
            en: Konfigurasi Instans
    TemplateTags:
      - 'acs:technical-solution:high-availability-architecture:high-availability-web-service-with-shared-storage-tech_solu_12'
    Hidden:
      - CommonName
{
  "ROSTemplateFormatVersion": "2015-09-01",
  "Description": {
    "zh-cn": "Build a high-availability web service that includes dual-zone ECS instances, an SLB instance, and NAS mounts. The service supports automatic configuration synchronization and public network access.",
    "en": "Constructing a highly available web service comprises dual availability zone ECS instances, a Load Balancer (SLB), Network Attached Storage (NAS) mounts, automatic configuration synchronization, and is accessible via the public internet."
  },
  "Parameters": {
    "NasZone1": {
      "AssociationProperty": "ALIYUN::ECS::Instance::ZoneId",
      "Type": "String",
      "Description": {
        "zh-cn": "Zone 1 must be different from Zone 2.",
        "en": "Availability zone 1 must be different from Availability zone 2."
      },
      "Label": {
        "zh-cn": "NAS Zone 1",
        "en": "NAS Availability Zone1"
      }
    },
    "NasZone2": {
      "AssociationProperty": "ALIYUN::ECS::Instance::ZoneId",
      "Type": "String",
      "Description": {
        "zh-cn": "Zone 2 must be different from Zone 1.",
        "en": "Availability zone 2 must be different from Availability zone 1."
      },
      "Label": {
        "zh-cn": "NAS Zone 2",
        "en": "NAS Availability Zone2"
      }
    },
    "CommonName": {
      "Default": "high-availability",
      "Type": "String"
    },
    "InstancePassword": {
      "Type": "String",
      "Description": {
        "zh-cn": "The logon password of the server. The password must be 8 to 30 characters in length and contain at least three of the following character types: uppercase letters, lowercase letters, digits, and special characters. Special characters include ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/",
        "en": "Server login password, Length 8~30, must contain three(Capital letters, lowercase letters, numbers, ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ Special symbol in)."
      },
      "MinLength": 8,
      "Label": {
        "zh-cn": "Instance Password",
        "en": "Instance Password"
      },
      "AllowedPattern": "[0-9A-Za-z\\_\\-\\&:;'<>,=%`~!@#\\(\\)\\$\\^\\*\\+\\|\\{\\}\\[\\]\\.\\?\\/]+$",
      "NoEcho": true,
      "MaxLength": 30,
      "AssociationProperty": "ALIYUN::ECS::Instance::Password",
      "ConstraintDescription": {
        "zh-cn": "The password must be 8 to 30 characters in length and contain at least three of the following character types: uppercase letters, lowercase letters, digits, and special characters. Special characters include ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/",
        "en": "Length 8~30, must contain three(Capital letters, lowercase letters, numbers, ()`~!@#$%^&*_-+=|{}[]:;'<>,.?/ Special symbol in)."
      }
    },
    "EcsInstanceType2": {
      "AssociationProperty": "ALIYUN::ECS::Instance::InstanceType",
      "AssociationPropertyMetadata": {
        "SystemDiskCategory": "cloud_essd",
        "InstanceChargeType": "PostPaid",
        "ZoneId": "${Zone2}"
      },
      "Type": "String",
      "Label": {
        "zh-cn": "Instance Type of Zone 2",
        "en": "Instance Type Of Availability Zone2"
      }
    },
    "Zone2": {
      "AssociationProperty": "ALIYUN::ECS::Instance::ZoneId",
      "Type": "String",
      "Description": {
        "zh-cn": "Zone 2 must be different from Zone 1.",
        "en": "Availability zone 2 must be different from Availability zone 1."
      },
      "Label": {
        "zh-cn": "vSwitch Zone 2",
        "en": "VSwitch Availability Zone2"
      }
    },
    "Zone1": {
      "AssociationProperty": "ALIYUN::ECS::Instance::ZoneId",
      "Type": "String",
      "Description": {
        "zh-cn": "Zone 1 must be different from Zone 2.",
        "en": "Availability zone 1 must be different from Availability zone 2."
      },
      "Label": {
        "zh-cn": "vSwitch Zone 1",
        "en": "VSwitch Availability Zone1"
      }
    },
    "EcsInstanceType1": {
      "AssociationProperty": "ALIYUN::ECS::Instance::InstanceType",
      "AssociationPropertyMetadata": {
        "SystemDiskCategory": "cloud_essd",
        "InstanceChargeType": "PostPaid",
        "ZoneId": "${Zone1}"
      },
      "Type": "String",
      "Label": {
        "zh-cn": "Instance Type of Zone 1",
        "en": "Instance Type Of Availability Zone1"
      }
    }
  },
  "Rules": {
    "DifferentZones2": {
      "Assertions": [
        {
          "Assert": {
            "Fn::Not": {
              "Fn::Equals": [
                {
                  "Ref": "NasZone1"
                },
                {
                  "Ref": "NasZone2"
                }
              ]
            }
          },
          "AssertDescription": "NAS Zones must be different"
        }
      ]
    },
    "DifferentZones1": {
      "Assertions": [
        {
          "Assert": {
            "Fn::Not": {
              "Fn::Equals": [
                {
                  "Ref": "Zone1"
                },
                {
                  "Ref": "Zone2"
                }
              ]
            }
          },
          "AssertDescription": "ECS Zones must be different"
        }
      ]
    }
  },
  "Outputs": {
    "ECS1URL": {
      "Description": "ECS 1 URL",
      "Value": {
        "Fn::Sub": [
          "https://ecs.console.alibabacloud.com/#/server/region/${region}?instanceIds=${InstanceID}",
          {
            "InstanceID": {
              "Fn::Select": [
                "0",
                {
                  "Fn::GetAtt": [
                    "EcsInstanceGroup1",
                    "InstanceIds"
                  ]
                }
              ]
            },
            "region": {
              "Ref": "ALIYUN::Region"
            }
          }
        ]
      }
    },
    "FileSystemId1": {
      "Description": {
        "zh-cn": "Master NAS",
        "en": "Master NAS"
      },
      "Value": {
        "Fn::Sub": [
          "https://nas.console.alibabacloud.com/${region}/filesystem/${InstanceID}",
          {
            "InstanceID": {
              "Fn::GetAtt": [
                "MasterFileSystem",
                "FileSystemId"
              ]
            },
            "region": {
              "Ref": "ALIYUN::Region"
            }
          }
        ]
      }
    },
    "ECS2URL": {
      "Description": "ECS 2 URL",
      "Value": {
        "Fn::Sub": [
          "https://ecs.console.alibabacloud.com/#/server/region/${region}?instanceIds=${InstanceID}",
          {
            "InstanceID": {
              "Fn::Select": [
                "0",
                {
                  "Fn::GetAtt": [
                    "EcsInstanceGroup1",
                    "InstanceIds"
                  ]
                }
              ]
            },
            "region": {
              "Ref": "ALIYUN::Region"
            }
          }
        ]
      }
    },
    "SlbIpAddress": {
      "Description": {
        "zh-cn": "The public IP address exposed to the Internet.",
        "en": "Public IP Addresses"
      },
      "Value": {
        "Fn::Sub": [
          "http://${ServerAddress}",
          {
            "ServerAddress": {
              "Fn::GetAtt": [
                "Slb",
                "IpAddress"
              ]
            }
          }
        ]
      }
    },
    "FileSystemId2": {
      "Description": {
        "zh-cn": "Secondary NAS",
        "en": "Backup NAS"
      },
      "Value": {
        "Fn::Sub": [
          "https://nas.console.alibabacloud.com/${region}/filesystem/${InstanceID}",
          {
            "InstanceID": {
              "Fn::GetAtt": [
                "BackupFileSystem",
                "FileSystemId"
              ]
            },
            "region": {
              "Ref": "ALIYUN::Region"
            }
          }
        ]
      }
    },
    "MountInfo1": {
      "Description": {
        "zh-cn": "NAS mount directory 1 on the ECS instance",
        "en": "NAS mounting directory 1 on ECS"
      },
      "Value": "/nas_master"
    },
    "MountInfo2": {
      "Description": {
        "zh-cn": "NAS mount directory 2 on the ECS instance",
        "en": "NAS mounting directory 2 on ECS"
      },
      "Value": "/nas_backup"
    }
  },
  "Resources": {
    "SlbListener": {
      "Type": "ALIYUN::SLB::Listener",
      "Properties": {
        "Protocol": "http",
        "HealthCheck": {
          "HealthCheckType": "http",
          "Interval": 2,
          "URI": "/",
          "UnhealthyThreshold": 3,
          "HealthyThreshold": 3,
          "Timeout": 5,
          "HttpCode": "http_2xx,http_3xx,http_4xx,http_5xx",
          "Port": 80
        },
        "ListenerPort": 80,
        "Bandwidth": 10,
        "BackendServerPort": 80,
        "LoadBalancerId": {
          "Ref": "Slb"
        }
      },
      "DependsOn": [
        "Slb"
      ]
    },
    "EcsSecurityGroup": {
      "Type": "ALIYUN::ECS::SecurityGroup",
      "Properties": {
        "SecurityGroupIngress": [
          {
            "Priority": 1,
            "PortRange": "80/80",
            "NicType": "internet",
            "SourceCidrIp": "0.0.0.0/0",
            "IpProtocol": "tcp"
          }
        ],
        "VpcId": {
          "Ref": "EcsVpc"
        },
        "SecurityGroupEgress": [
          {
            "Priority": 1,
            "PortRange": "-1/-1",
            "DestCidrIp": "0.0.0.0/0",
            "NicType": "internet",
            "IpProtocol": "all"
          },
          {
            "Priority": 1,
            "PortRange": "-1/-1",
            "DestCidrIp": "0.0.0.0/0",
            "NicType": "intranet",
            "IpProtocol": "all"
          }
        ],
        "SecurityGroupName": {
          "Fn::Sub": "${CommonName}_sg"
        }
      }
    },
    "MasterNasMountTarget": {
      "Type": "ALIYUN::NAS::MountTarget",
      "Properties": {
        "NetworkType": "Vpc",
        "FileSystemId": {
          "Ref": "MasterFileSystem"
        },
        "VpcId": {
          "Ref": "EcsVpc"
        },
        "VSwitchId": {
          "Ref": "EcsVSwitch3"
        },
        "AccessGroupName": "DEFAULT_VPC_GROUP_NAME"
      }
    },
    "EcsVSwitch4": {
      "Type": "ALIYUN::ECS::VSwitch",
      "Properties": {
        "VSwitchName": {
          "Fn::Sub": "${CommonName}_vsw_002"
        },
        "VpcId": {
          "Ref": "EcsVpc"
        },
        "CidrBlock": "192.168.4.0/24",
        "ZoneId": {
          "Ref": "NasZone2"
        }
      }
    },
    "MasterFileSystem": {
      "Type": "ALIYUN::NAS::FileSystem",
      "Properties": {
        "StorageType": "Capacity",
        "ProtocolType": "NFS",
        "VpcId": {
          "Ref": "EcsVpc"
        },
        "Description": "MasterNAS",
        "ZoneId": {
          "Ref": "NasZone1"
        }
      }
    },
    "EcsVSwitch2": {
      "Type": "ALIYUN::ECS::VSwitch",
      "Properties": {
        "VSwitchName": {
          "Fn::Sub": "${CommonName}_vsw_002"
        },
        "VpcId": {
          "Ref": "EcsVpc"
        },
        "CidrBlock": "192.168.2.0/24",
        "ZoneId": {
          "Ref": "Zone2"
        }
      }
    },
    "EcsVSwitch3": {
      "Type": "ALIYUN::ECS::VSwitch",
      "Properties": {
        "VSwitchName": {
          "Fn::Sub": "${CommonName}_vsw_002"
        },
        "VpcId": {
          "Ref": "EcsVpc"
        },
        "CidrBlock": "192.168.3.0/24",
        "ZoneId": {
          "Ref": "NasZone1"
        }
      }
    },
    "EcsVSwitch1": {
      "Type": "ALIYUN::ECS::VSwitch",
      "Properties": {
        "VSwitchName": {
          "Fn::Sub": "${CommonName}_vsw_001"
        },
        "VpcId": {
          "Ref": "EcsVpc"
        },
        "CidrBlock": "192.168.1.0/24",
        "ZoneId": {
          "Ref": "Zone1"
        }
      }
    },
    "BackupFileSystem": {
      "Type": "ALIYUN::NAS::FileSystem",
      "Properties": {
        "StorageType": "Capacity",
        "ProtocolType": "NFS",
        "VpcId": {
          "Ref": "EcsVpc"
        },
        "Description": "BackupNAS",
        "ZoneId": {
          "Ref": "NasZone2"
        }
      }
    },
    "BackupNasMountTarget": {
      "Type": "ALIYUN::NAS::MountTarget",
      "Properties": {
        "NetworkType": "Vpc",
        "FileSystemId": {
          "Ref": "BackupFileSystem"
        },
        "VpcId": {
          "Ref": "EcsVpc"
        },
        "VSwitchId": {
          "Ref": "EcsVSwitch4"
        },
        "AccessGroupName": "DEFAULT_VPC_GROUP_NAME"
      }
    },
    "EcsInstanceGroup1": {
      "Type": "ALIYUN::ECS::InstanceGroup",
      "Properties": {
        "SystemDiskCategory": "cloud_essd",
        "VpcId": {
          "Ref": "EcsVpc"
        },
        "SecurityGroupId": {
          "Ref": "EcsSecurityGroup"
        },
        "SystemDiskSize": 40,
        "ImageId": "aliyun_3_x64_20G_alibase_20230727.vhd",
        "SpotStrategy": "SpotAsPriceGo",
        "IoOptimized": "optimized",
        "VSwitchId": {
          "Ref": "EcsVSwitch1"
        },
        "Password": {
          "Ref": "InstancePassword"
        },
        "InstanceName": {
          "Fn::Sub": "${CommonName}_ecs_001"
        },
        "InstanceType": {
          "Ref": "EcsInstanceType1"
        },
        "ZoneId": {
          "Ref": "Zone1"
        },
        "MaxAmount": 1
      }
    },
    "EcsInstanceGroup2": {
      "Type": "ALIYUN::ECS::InstanceGroup",
      "Properties": {
        "SystemDiskCategory": "cloud_essd",
        "VpcId": {
          "Ref": "EcsVpc"
        },
        "SecurityGroupId": {
          "Ref": "EcsSecurityGroup"
        },
        "SystemDiskSize": 40,
        "ImageId": "aliyun_3_x64_20G_alibase_20230727.vhd",
        "SpotStrategy": "SpotAsPriceGo",
        "IoOptimized": "optimized",
        "VSwitchId": {
          "Ref": "EcsVSwitch2"
        },
        "Password": {
          "Ref": "InstancePassword"
        },
        "InstanceName": {
          "Fn::Sub": "${CommonName}_ecs_002"
        },
        "InstanceType": {
          "Ref": "EcsInstanceType2"
        },
        "ZoneId": {
          "Ref": "Zone2"
        },
        "MaxAmount": 1
      }
    },
    "EcsVpc": {
      "Type": "ALIYUN::ECS::VPC",
      "Properties": {
        "VpcName": {
          "Fn::Sub": "${CommonName}_vpc"
        },
        "CidrBlock": "192.168.0.0/16"
      }
    },
    "SlbBackendServerAttachment": {
      "Type": "ALIYUN::SLB::BackendServerAttachment",
      "Properties": {
        "BackendServerList": {
          "Fn::ListMerge": [
            {
              "Fn::GetAtt": [
                "EcsInstanceGroup1",
                "InstanceIds"
              ]
            },
            {
              "Fn::GetAtt": [
                "EcsInstanceGroup2",
                "InstanceIds"
              ]
            }
          ]
        },
        "BackendServerWeightList": [
          100,
          100
        ],
        "LoadBalancerId": {
          "Ref": "Slb"
        }
      }
    },
    "Slb": {
      "Type": "ALIYUN::SLB::LoadBalancer",
      "Properties": {
        "AddressType": "internet",
        "LoadBalancerName": {
          "Fn::Sub": "${CommonName}-slb"
        },
        "InstanceChargeType": "PayByCLCU",
        "PayType": "PayOnDemand"
      }
    },
    "InstanceRunCommand": {
      "Type": "ALIYUN::ECS::RunCommand",
      "Properties": {
        "CommandContent": {
          "Fn::Sub": "#!/bin/bash\nif [ ! -f .ros.provision ]; then\n  echo \"Name: High-availability web service with shared storage\" > .ros.provision\nfi\n\nname=$(grep \"^Name:\" .ros.provision | awk -F':' '{print $2}' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')\nif [[ \"$name\" != \"High-availability web service with shared storage\" ]]; then\n  echo \"This instance has already been configured using the one-click deployment of the \\\"$name\\\" tutorial. You cannot use the one-click deployment of this tutorial.\"\n  exit 0\nfi\n\necho \"#########################\"\necho \"# Check Network\"\necho \"#########################\"\nping -c 2 -W 2 aliyun.com > /dev/null\nif [[ $? -ne 0 ]]; then\n  echo \"The current instance cannot access the public network.\"\n  exit 0\nfi\n\nif ! grep -q \"^Step1: Prepare Environment$\" .ros.provision; then\n  echo \"#########################\"\n  echo \"# Prepare Environment\"\n  echo \"#########################\"\n  systemctl status firewalld\n  systemctl stop firewalld\n  echo \"Step1: Prepare Environment\" >> .ros.provision\nelse\n  echo \"#########################\"\n  echo \"# Environment has been ready\"\n  echo \"#########################\"\nfi\n\nif ! grep -q \"^Step2: Install Nginx and deploy service$\" .ros.provision; then\n  echo \"#########################\"\n  echo \"# Install Nginx\"\n  echo \"#########################\"\n  sudo yum -y install nginx\n  sudo wget -O /usr/share/nginx/html/index.html https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20231013/jhgg/index.html\n  sudo wget -O /usr/share/nginx/html/lipstick.png https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20230925/zevs/lipstick.png\n  sudo systemctl start nginx\n  sudo systemctl enable nginx\n  echo \"Step2: Install Nginx and deploy service\" >> .ros.provision\nelse\n  echo \"#########################\"\n  echo \"# Nginx has been installed\"\n  echo \"#########################\"\nfi\n\nif ! grep -q \"^Step3: Mount to the ECS\" .ros.provision; then\n  echo \"#########################\"\n  echo \"# Mount to the ECS\"\n  echo \"#########################\"\n  mkdir /nas_master\n  mkdir /nas_backup\n  sudo yum install -y nfs-utils\n  sudo echo \"options sunrpc tcp_slot_table_entries=128\" >>  /etc/modprobe.d/sunrpc.conf\n  sudo echo \"options sunrpc tcp_max_slot_table_entries=128\" >>  /etc/modprobe.d/sunrpc.conf\n  sudo mount -t nfs -o vers=3,nolock,proto=tcp,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport ${MasterNasMountTarget.MountTargetDomain}:/ /nas_master\n  sudo mount -t nfs -o vers=3,nolock,proto=tcp,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport ${BackupNasMountTarget.MountTargetDomain}:/ /nas_backup\n\n  sudo echo \"${MasterNasMountTarget.MountTargetDomain}:/ /nas_master nfs vers=3,nolock,proto=tcp,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,_netdev,noresvport 0 0\" >> /etc/fstab\n  \n  sudo echo \"${BackupNasMountTarget.MountTargetDomain}:/ /nas_backup nfs vers=3,nolock,proto=tcp,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,_netdev,noresvport 0 0\" >> /etc/fstab\n\n  df -h | grep aliyun\nelse\n  echo \"#########################\"\n  echo \"# The ECS has been attached to the Nas\"\n  echo \"#########################\"\nfi\n\nif ! grep -q \"^Step4: Shared file$\" .ros.provision; then\n  echo \"#########################\"\n  echo \"# Shared file\"\n  echo \"#########################\"\n  sudo cp -Lvr /usr/share/nginx/html /nas_master\n  sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak\n  echo \"Step4: Shared file\" >> .ros.provision\nelse\n  echo \"#########################\"\n  echo \"# File has been Shared\"\n  echo \"#########################\"\nfi\n\nif ! grep -q \"^Step5: Install inotify-tools, rsync$\" .ros.provision; then\n  echo \"#########################\"\n  echo \"# Install inotify-tools, rsync\"\n  echo \"#########################\"\n  sudo yum install -y inotify-tools rsync\n  echo \"Step6: Install inotify-tools, rsync\" >> .ros.provision\nelse\n  echo \"#########################\"\n  echo \"# Inotify-tools has been installed\"\n  echo \"#########################\"\nfi\nif ! grep -q \"^Step6: Install synchronization server$\" .ros.provision; then\n  echo \"#########################\"\n  echo \"# Install synchronization server\"\n  echo \"#########################\"\n  sudo wget -P /etc/systemd/system/ https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20231017/pftz/sync_nas.sh\n  sudo wget -P /etc/systemd/system/ https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/en-US/20230925/wmaj/sync_check_switch.sh\n  sudo chmod +x /etc/systemd/system/sync_nas.sh\n  sudo chmod +x /etc/systemd/system/sync_check_switch.sh\n  cat > /etc/systemd/system/sync-check-switch.service << \\EOF\n[Unit]\nDescription=Sync Check Switch\nAfter=network.target\n\n[Service]\nExecStart=/etc/systemd/system/sync_check_switch.sh\nRestartSec=3\nRestart=always\n\n[Install]\nWantedBy=default.target\nEOF\n\n  cat > /etc/systemd/system/sync-nas.service << \\EOF\n[Unit]\nDescription=Sync NAS Service\nAfter=network.target\n\n[Service]\nExecStart=/etc/systemd/system/sync_nas.sh\nRestart=always\nRestartSec=3\n\n[Install]\nWantedBy=default.target\nEOF\n\n  sudo systemctl daemon-reload\n  sudo systemctl start sync-nas.service\n  sudo systemctl enable sync-check-switch.service\n  sudo systemctl start sync-check-switch.service\n  sudo systemctl enable sync-nas.service\n  echo \"Step6: Install \" >> .ros.provision\nelse\n  echo \"#########################\"\n  echo \"# Synchronization server has been installed\"\n  echo \"#########################\"\nfi"
        },
        "Type": "RunShellScript",
        "Sync": true,
        "InstanceIds": [
          {
            "Ref": "EcsInstanceGroup1"
          },
          {
            "Ref": "EcsInstanceGroup2"
          }
        ],
        "Timeout": "300"
      }
    }
  },
  "Metadata": {
    "ALIYUN::ROS::Interface": {
      "ParameterGroups": [
        {
          "Parameters": [
            "Zone1",
            "Zone2",
            "NasZone1",
            "NasZone2"
          ],
          "Label": {
            "default": {
              "zh-cn": "Zone Configuration",
              "en": "Availability Zone"
            }
          }
        },
        {
          "Parameters": [
            "EcsInstanceType1",
            "EcsInstanceType2",
            "InstancePassword"
          ],
          "Label": {
            "default": {
              "zh-cn": "ECS Instance Configuration",
              "en": "Instance Configure"
            }
          }
        }
      ],
      "TemplateTags": [
        "acs:technical-solution:high-availability-architecture:high-availability-web-service-with-shared-storage-tech_solu_12"
      ],
      "Hidden": [
        "CommonName"
      ]
    }
  }
}

Untuk contoh lainnya, lihat templat publik yang berisi resource ini.