Skip to content

Commit bd31bcf

Browse files
authored
Add database provisioner, ALB and bastion host (#28)
- Add database provisioner, currently support H2 and rds-postgresql. - Add an AWS ALB so that we can access the SkyWalking UI via ALB, instead of doing port forward. - For security reason, add a bastion host and all operations to OAP and UI instances are done via bastion host as a proxy. - Simplify some command line options by adding them into files. - Generate Terraform docs for inputs, outputs, resources, etc.
1 parent e6ba72d commit bd31bcf

23 files changed

+702
-110
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ aws/terraform.tfstate.backup
1818
ansible/local.var.yaml
1919
ansible/inventory
2020
!ansible/inventory/template
21+
.terraform.tfstate.lock.info

README.md

+30-28
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,7 @@ terraform init
4242

4343
The script is designed with modularity and reusability in mind. Various parameters like region, instance count, instance type, etc., are exposed as variables for easier customization.
4444

45-
#### Variables:
46-
47-
| Variable Name | Description | Default Value |
48-
|---------------------|------------------------------------------------------|-----------------------------|
49-
| `oap_instance_count`| Number of SkyWalking OAP instances | `1` |
50-
| `ui_instance_count` | Number of SkyWalking UI instances | `1` |
51-
| `region` | AWS region where resources will be provisioned | `us-east-1` |
52-
| `instance_type` | AWS instance type for SkyWalking OAP and UI | `t2.medium` |
53-
| `public_key_path` | Path where the SSH key for instances will be stored | `~/.ssh` |
54-
| `extra_tags` | Additional tags that can be applied to all resources | `{}` |
45+
For the full configuration list, please refer to [the doc](/aws/README.md).
5546

5647
To modify the default values, you can create a `terraform.tfvars` file in the same directory as your Terraform script:
5748

@@ -60,7 +51,6 @@ oap_instance_count = 2
6051
ui_instance_count = 2
6152
region = "us-west-1"
6253
instance_type = "t2.large"
63-
public_key_path = "/path/to/your/desired/location"
6454
extra_tags = {
6555
"Environment" = "Production"
6656
}
@@ -75,17 +65,24 @@ terraform plan
7565
terraform apply
7666
```
7767

68+
After all the resources are created, you can head to the
69+
[Ansible part](#ansible) to start deploying SkyWalking.
70+
7871
### 4. Accessing the Resources
7972

80-
Once the resources are created:
73+
#### SSH into bastion host (Optional)
8174

82-
- **SkyWalking OAP and UI instances**: You can SSH into the instances using the generated key pair. The public IPs of these instances are stored in local files (`oap-server` and `ui-server` respectively) under the `ansible/inventory/` directory, relative to the module's path.
75+
You don't usually need to SSH into the bastion host, but if you want to, you can
76+
SSH into the bastion host with the command:
8377

84-
```bash
85-
ssh -i /path/to/skywalking.pem ec2-user@<INSTANCE_PUBLIC_IP>
78+
```shell
79+
KEY_FILE=$(terraform output -raw ssh-user-key-file)
80+
BASTION_IP=$(terraform output -json bastion_ips | jq -r '.[0]')
81+
82+
ssh -i "$KEY_FILE" ec2-user@"$BASTION_IP"
8683
```
8784

88-
- **Security Groups**: Two security groups are created:
85+
- **Security Attention**: two security rules are created for the bastion host:
8986
- `ssh-access`: Allows SSH access from any IP (`0.0.0.0/0`). **Please note** that this is potentially insecure and you should restrict the IP range wherever possible.
9087
- `public-egress-access`: Allows egress access to the internet for the instances.
9188

@@ -118,26 +115,18 @@ This guide provides steps on using Ansible to install Apache SkyWalking on AWS i
118115

119116
## Instructions
120117

121-
### 1. Change diroectory and set the SSH Key File Path
118+
### 1. Change diroectory
122119

123-
Save the SSH key file path generated by Terraform to a variable for future use:
124-
125-
```
120+
```shell
126121
cd ../ansible/
127-
SSH_KEY_FILE=$(terraform -chdir=../aws output -raw ssh-user-key-file)
128-
echo $SSH_KEY_FILE
129122
```
130123

131-
**Expected Output**:
132-
133-
You should see a file path similar to: `/Users/kezhenxu94/.ssh/skywalking.pem`
134-
135124
### 2. Test Connectivity to the EC2 Instances
136125

137126
Before installing SkyWalking, ensure that you can connect to the EC2 instances:
138127

139128
```
140-
ANSIBLE_HOST_KEY_CHECKING=False ansible -m ping all -u ec2-user --private-key "$SSH_KEY_FILE"
129+
ansible -m ping all -u ec2-user
141130
```
142131

143132
**Expected Output**:
@@ -165,7 +154,7 @@ You should see output for each IP with a `SUCCESS` status:
165154
After confirming connectivity, proceed to install Apache SkyWalking using the Ansible playbook:
166155

167156
```
168-
ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -u ec2-user --private-key "$SSH_KEY_FILE" playbooks/install-skywalking.yml
157+
ansible-playbook -u ec2-user playbooks/install-skywalking.yml -i inventory/skywalking.yaml
169158
```
170159

171160
### 4. Configurations
@@ -196,3 +185,16 @@ skywalking_ui_environment: {}
196185
skywalking_oap_environment: {}
197186

198187
```
188+
189+
### 5. Accessing SkyWalking UI!
190+
191+
After the installation is complete, you can go back to the aws folder and get
192+
the ALB domain name address that can be used to access the SkyWalking UI:
193+
194+
```shell
195+
cd ../aws
196+
terraform output -raw alb_dns_name
197+
```
198+
199+
And you can open your browser and access the SkyWalking UI with the address.
200+

ansible/inventory/template/skywalking.yaml.tftpl

+18-4
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,35 @@
1616
# specific language governing permissions and limitations
1717
# under the License.
1818
#
19+
20+
proxy:
21+
${bastion.public_ip}:
22+
1923
skywalking:
24+
vars:
25+
ansible_ssh_private_key_file: ${private_key_file}
26+
ansible_ssh_user: ec2-user
27+
ansible_ssh_common_args: '-o StrictHostKeyChecking=no -o ProxyCommand="ssh -i ${private_key_file} -o StrictHostKeyChecking=no -W %h:%p -q ec2-user@${bastion.public_ip}"'
2028
children:
2129
skywalking_oap:
2230
skywalking_ui:
2331

2432
skywalking_oap:
2533
hosts:
2634
%{ for oap in oap_instances ~}
27-
${oap.public_ip}:
28-
private_ip: ${oap.private_ip}
35+
${oap.private_ip}:
2936
%{ endfor ~}
37+
vars:
38+
database:
39+
type: ${database_type}
40+
host: ${database_host}
41+
port: ${database_port}
42+
name: ${database_name}
43+
user: ${database_user}
44+
password: ${database_password}
3045

3146
skywalking_ui:
3247
hosts:
3348
%{ for ui in ui_instances ~}
34-
${ui.public_ip}:
35-
private_ip: ${ui.private_ip}
49+
${ui.private_ip}:
3650
%{ endfor ~}

ansible/roles/skywalking/tasks/main.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,15 @@
5252
src: skywalking-ui.env.j2
5353
dest: /home/skywalking/webapp.env
5454
owner: skywalking
55-
mode: "0660"
55+
mode: "0600"
5656
when: inventory_hostname in groups['skywalking_ui']
5757

5858
- name: Generate environment file for OAP service
5959
template:
6060
src: skywalking-oap.env.j2
6161
dest: /home/skywalking/oap.env
6262
owner: skywalking
63-
mode: "0660"
63+
mode: "0600"
6464
when: inventory_hostname in groups['skywalking_oap']
6565

6666
- name: Check hostgroup size
@@ -69,7 +69,7 @@
6969
oap_init_node: "{{ [groups['skywalking_oap'][0]] }}"
7070

7171
- name: Run the OAPSericeInit script
72-
command: "sudo -u skywalking /usr/local/skywalking/bin/oapServiceInit.sh"
72+
command: "sudo -u skywalking -- sh -c 'set -a; source /home/skywalking/oap.env; set +a; /usr/local/skywalking/bin/oapServiceInit.sh'"
7373
when: inventory_hostname in oap_init_node
7474

7575
- name: Generate systemd unit file for oap service

ansible/roles/skywalking/templates/skywalking-oap.env.j2

+14
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,20 @@
1616
# specific language governing permissions and limitations
1717
# under the License.
1818
#
19+
20+
{% set database = hostvars[inventory_hostname]["database"] %}
21+
{% set storage = database['type'] %}
22+
23+
{% if storage and (storage | length) %}
24+
SW_STORAGE={{ storage | regex_replace('^rds-', '')}}
25+
{% endif %}
26+
27+
{% if "postgresql" in storage %}
28+
SW_JDBC_URL=jdbc:postgresql://{{ database["host"] }}:{{ database["port"] }}/{{ database["name"] }}
29+
SW_DATA_SOURCE_USER={{ database['user'] }}
30+
SW_DATA_SOURCE_PASSWORD={{ database['password'] }}
31+
{% endif %}
32+
1933
{% for key, value in skywalking_oap_environment.items() %}
2034
{{ key }}="{{ value }}"
2135
{% endfor %}

ansible/roles/skywalking/templates/skywalking-oap.service.j2

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ After=network.target
2121
Type=simple
2222
User=skywalking
2323
Group=skywalking
24-
ExecStart=/usr/local/skywalking/bin/oapService.sh
24+
EnvironmentFile=/home/skywalking/oap.env
25+
ExecStart=/usr/local/skywalking/bin/oapServiceNoInit.sh
2526
TimeoutSec=300
2627
KillMode=process
2728
ExecReload=/bin/kill -HUP $MAINPID

ansible/roles/skywalking/templates/skywalking-ui.env.j2

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@
2020
{{ key }}="{{ value }}"
2121
{% endfor %}
2222

23-
SW_OAP_ADDRESS="{% for host in groups['skywalking_oap'] %}http://{{ hostvars[host].private_ip }}:{{ skywalking_ui_environment['SW_CORE_GRPC_PORT'] | default ('12800') }}{% if not loop.last %},{% endif %}{% endfor %}"
24-
SW_ZIPKIN_ADDRESS="{% for host in groups['skywalking_oap'] %}http://{{ hostvars[host].private_ip }}:{{ skywalking_ui_environment['SW_QUERY_ZIPKIN_REST_PORT'] | default ('9412') }}{% if not loop.last %},{% endif %}{% endfor %}"
23+
SW_OAP_ADDRESS="{% for host in groups['skywalking_oap'] %}http://{{ hostvars[host].inventory_hostname }}:{{ skywalking_ui_environment['SW_CORE_GRPC_PORT'] | default ('12800') }}{% if not loop.last %},{% endif %}{% endfor %}"
24+
SW_ZIPKIN_ADDRESS="{% for host in groups['skywalking_oap'] %}http://{{ hostvars[host].inventory_hostname }}:{{ skywalking_ui_environment['SW_QUERY_ZIPKIN_REST_PORT'] | default ('9412') }}{% if not loop.last %},{% endif %}{% endfor %}"
2525

aws/README.md

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<!-- BEGIN_TF_DOCS -->
2+
## Requirements
3+
4+
No requirements.
5+
6+
## Providers
7+
8+
| Name | Version |
9+
|------|---------|
10+
| <a name="provider_aws"></a> [aws](#provider\_aws) | 5.10.0 |
11+
| <a name="provider_local"></a> [local](#provider\_local) | 2.4.0 |
12+
| <a name="provider_random"></a> [random](#provider\_random) | 3.5.1 |
13+
| <a name="provider_tls"></a> [tls](#provider\_tls) | 4.0.4 |
14+
15+
## Modules
16+
17+
| Name | Source | Version |
18+
|------|--------|---------|
19+
| <a name="module_alb"></a> [alb](#module\_alb) | terraform-aws-modules/alb/aws | ~> 8.0 |
20+
| <a name="module_rds"></a> [rds](#module\_rds) | terraform-aws-modules/rds/aws | ~> 5.0 |
21+
| <a name="module_vpc"></a> [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | ~> 5.0 |
22+
23+
## Resources
24+
25+
| Name | Type |
26+
|------|------|
27+
| [aws_instance.bastion](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource |
28+
| [aws_instance.skywalking-oap](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource |
29+
| [aws_instance.skywalking-ui](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource |
30+
| [aws_key_pair.ssh-user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/key_pair) | resource |
31+
| [aws_security_group.allow_apps](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
32+
| [aws_security_group.bastion](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
33+
| [aws_security_group.public-egress-access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
34+
| [aws_security_group.skywalking-oap](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
35+
| [aws_security_group.skywalking-ui](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
36+
| [local_file.inventories](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource |
37+
| [local_file.ssh-user](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource |
38+
| [random_password.rds_password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource |
39+
| [tls_private_key.ssh-user](https://registry.terraform.io/providers/hashicorp/tls/latest/docs/resources/private_key) | resource |
40+
| [aws_ami.amazon-linux](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source |
41+
| [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source |
42+
43+
## Inputs
44+
45+
| Name | Description | Type | Default | Required |
46+
|------|-------------|------|---------|:--------:|
47+
| <a name="input_access_key"></a> [access\_key](#input\_access\_key) | Access key of the AWS account, if you have configured AWS CLI, you can leave it empty. | `string` | `""` | no |
48+
| <a name="input_bastion_enabled"></a> [bastion\_enabled](#input\_bastion\_enabled) | Enable bastion host, if you want to access the instances via SSH, you must enable it. | `bool` | `true` | no |
49+
| <a name="input_bastion_instance_type"></a> [bastion\_instance\_type](#input\_bastion\_instance\_type) | CPU, memory, storage and networking capacity for bastion host | `string` | `"t2.micro"` | no |
50+
| <a name="input_cidr"></a> [cidr](#input\_cidr) | CIDR for database tier | `string` | `"11.0.0.0/16"` | no |
51+
| <a name="input_cluster_name"></a> [cluster\_name](#input\_cluster\_name) | Name of the cluster | `string` | `"skywalking-cluster"` | no |
52+
| <a name="input_database_subnets"></a> [database\_subnets](#input\_database\_subnets) | CIDR used for database subnets | `set(string)` | <pre>[<br> "11.0.104.0/24",<br> "11.0.105.0/24",<br> "11.0.106.0/24"<br>]</pre> | no |
53+
| <a name="input_db_instance_class"></a> [db\_instance\_class](#input\_db\_instance\_class) | Instance class for the database | `string` | `"db.t3.medium"` | no |
54+
| <a name="input_db_max_storage_size"></a> [db\_max\_storage\_size](#input\_db\_max\_storage\_size) | Maximum storage size for the database, in GB | `number` | `100` | no |
55+
| <a name="input_db_name"></a> [db\_name](#input\_db\_name) | Name of the database | `string` | `"skywalking"` | no |
56+
| <a name="input_db_password"></a> [db\_password](#input\_db\_password) | Password for the database, if not set, a random password will be generated. | `string` | `null` | no |
57+
| <a name="input_db_storage_size"></a> [db\_storage\_size](#input\_db\_storage\_size) | Storage size for the database, in GB | `number` | `5` | no |
58+
| <a name="input_db_username"></a> [db\_username](#input\_db\_username) | Username for the database | `string` | `"skywalking"` | no |
59+
| <a name="input_extra_tags"></a> [extra\_tags](#input\_extra\_tags) | Additional tags to be added to all resources | `map(string)` | `{}` | no |
60+
| <a name="input_instance_type"></a> [instance\_type](#input\_instance\_type) | CPU, memory, storage and networking capacity for OAP and UI instances | `string` | `"t2.medium"` | no |
61+
| <a name="input_oap_instance_count"></a> [oap\_instance\_count](#input\_oap\_instance\_count) | Number of OAP instances, if you want to use H2 storage, you must set it to 1. | `number` | `1` | no |
62+
| <a name="input_private_subnets"></a> [private\_subnets](#input\_private\_subnets) | CIDR used for private subnets | `set(string)` | <pre>[<br> "11.0.1.0/24",<br> "11.0.2.0/24",<br> "11.0.3.0/24"<br>]</pre> | no |
63+
| <a name="input_public_key_path"></a> [public\_key\_path](#input\_public\_key\_path) | Path to store the key file for SSH access to the instances. | `string` | `"~/.ssh"` | no |
64+
| <a name="input_public_subnets"></a> [public\_subnets](#input\_public\_subnets) | CIDR used for public subnets | `set(string)` | <pre>[<br> "11.0.101.0/24",<br> "11.0.102.0/24",<br> "11.0.103.0/24"<br>]</pre> | no |
65+
| <a name="input_region"></a> [region](#input\_region) | Physical location for clustered data centers. | `string` | `"us-east-1"` | no |
66+
| <a name="input_secret_key"></a> [secret\_key](#input\_secret\_key) | Secret key of the AWS account, if you have configured AWS CLI, you can leave it empty. | `string` | `""` | no |
67+
| <a name="input_storage"></a> [storage](#input\_storage) | Storage type for SkyWalking OAP, can be 'h2', or 'rds-postgresql' | `string` | `"rds-postgresql"` | no |
68+
| <a name="input_ui_instance_count"></a> [ui\_instance\_count](#input\_ui\_instance\_count) | Number of UI instances | `number` | `1` | no |
69+
70+
## Outputs
71+
72+
| Name | Description |
73+
|------|-------------|
74+
| <a name="output_alb_dns_name"></a> [alb\_dns\_name](#output\_alb\_dns\_name) | The domain name of the ALB that can be used to access SkyWalking UI. |
75+
| <a name="output_bastion_ips"></a> [bastion\_ips](#output\_bastion\_ips) | The public IP that can be used to SSH into the bastion host. |
76+
| <a name="output_database_address"></a> [database\_address](#output\_database\_address) | The database address |
77+
| <a name="output_database_name"></a> [database\_name](#output\_database\_name) | The database name |
78+
| <a name="output_database_password"></a> [database\_password](#output\_database\_password) | The database password |
79+
| <a name="output_database_port"></a> [database\_port](#output\_database\_port) | The database port |
80+
| <a name="output_database_username"></a> [database\_username](#output\_database\_username) | The database username |
81+
| <a name="output_skywalking_oap_ips"></a> [skywalking\_oap\_ips](#output\_skywalking\_oap\_ips) | The private IPs of the OAP instances |
82+
| <a name="output_skywalking_ui_ips"></a> [skywalking\_ui\_ips](#output\_skywalking\_ui\_ips) | The IPs of the SkyWalking UI instances |
83+
| <a name="output_ssh-user-key-file"></a> [ssh-user-key-file](#output\_ssh-user-key-file) | The SSH key file that can be used to connect to the bastion instance. |
84+
<!-- END_TF_DOCS -->

aws/alb-main.tf

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one or more
2+
# contributor license agreements. See the NOTICE file distributed with
3+
# this work for additional information regarding copyright ownership.
4+
# The ASF licenses this file to You under the Apache License, Version 2.0
5+
# (the "License"); you may not use this file except in compliance with
6+
# the License. You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
module "alb" {
17+
source = "terraform-aws-modules/alb/aws"
18+
version = "~> 8.0"
19+
20+
name = var.cluster_name
21+
22+
load_balancer_type = "application"
23+
24+
vpc_id = module.vpc.vpc_id
25+
subnets = module.vpc.public_subnets
26+
security_groups = [module.vpc.default_security_group_id]
27+
28+
security_group_rules = {
29+
ingress_all_http = {
30+
type = "ingress"
31+
from_port = 80
32+
to_port = 80
33+
protocol = "tcp"
34+
description = "Allow HTTP traffic"
35+
cidr_blocks = ["0.0.0.0/0"]
36+
}
37+
egress_all = {
38+
type = "egress"
39+
from_port = 0
40+
to_port = 0
41+
protocol = "-1"
42+
cidr_blocks = ["0.0.0.0/0"]
43+
}
44+
}
45+
46+
target_groups = [
47+
{
48+
name_prefix = substr(var.cluster_name, 0, 6)
49+
backend_protocol = "HTTP"
50+
backend_port = 8080
51+
target_type = "instance"
52+
targets = [
53+
for i, ui in aws_instance.skywalking-ui : {
54+
target_id = ui.id
55+
port = 8080
56+
}
57+
]
58+
}
59+
]
60+
61+
http_tcp_listeners = [
62+
{
63+
port = 80
64+
protocol = "HTTP"
65+
target_group_index = 0
66+
}
67+
]
68+
69+
tags = var.extra_tags
70+
}

0 commit comments

Comments
 (0)