diff --git a/README.md b/README.md index 3b34f05..3ae8ceb 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,7 @@ for each. Details for each use case can be found in the linked documents. - [Running builds locally](docs/building-locally.md) - [Running builds on Hetzner Cloud](docs/building-with-hetzner-cloud.md) +- [Running builds on AWS EC2](docs/building-with-aws-ec2.md) - [Running builds with tmt](docs/building-with-tmt.md) Some common scenarios are also documented: diff --git a/aws-ec2.yaml b/aws-ec2.yaml new file mode 100644 index 0000000..d8b9ebd --- /dev/null +++ b/aws-ec2.yaml @@ -0,0 +1,52 @@ +--- +- name: instantiate-builder + hosts: localhost + roles: + - aws-ec2-instantiate + +- name: initiate build + hosts: "asz_server" + remote_user: ec2-user + roles: + - common + +- name: prepare sample images + hosts: "asz_server" + remote_user: ec2-user + roles: + - prepare-sample-images + +- name: prepare custom images + hosts: "asz_server" + remote_user: ec2-user + roles: + - prepare-custom-images + +- name: prepare distro configs + hosts: "asz_server" + remote_user: ec2-user + roles: + - prepare-distro-configs + +- name: prepare osbuild + hosts: "asz_server" + remote_user: ec2-user + roles: + - prepare-osbuild + +- name: run make + hosts: "asz_server" + remote_user: ec2-user + roles: + - run-make + +- name: run make for osbuildvm-images + hosts: "asz_server" + remote_user: ec2-user + roles: + - run-make-osbuildvm + +- name: teardown-builder + hosts: localhost + roles: + - aws-ec2-teardown diff --git a/config.yaml b/config.yaml index 01ab6e1..cbb9cb0 100644 --- a/config.yaml +++ b/config.yaml @@ -68,3 +68,14 @@ hcloud_x86_64_image: "centos-stream-9" hcloud_x86_64_location: "fsn1" hcloud_x86_64_ssh_keys: - "michael@fedora" + +# AWS EC2 configuration +aws_ec2_aarch64_instance_type: "t4g.medium" +aws_ec2_aarch64_ami: "ami-0249b4054bde4661d" # CentOS Stream 9 aarch64 20240212 +aws_ec2_aarch64_region: "eu-central-1" +aws_ec2_aarch64_ssh_key: "michael@fedora" + +aws_ec2_x86_64_instance_type: "t3.medium" +aws_ec2_x86_64_ami: "ami-000dc02a9a29648e7" # CentOS Stream 9 x86_64 20240212 +aws_ec2_x86_64_region: "eu-central-1" +aws_ec2_x86_64_ssh_key: "michael@fedora" diff --git a/docs/building-with-aws-ec2.md b/docs/building-with-aws-ec2.md new file mode 100644 index 0000000..4758232 --- /dev/null +++ b/docs/building-with-aws-ec2.md @@ -0,0 +1,54 @@ +## Running Builds on AWS with EC2 + +Zeppelin can orchestrate spawning an AWS EC2 server instance (Virtual Machine), +running the build operations on said server, fetching the results back to the +users computer, and deleting the EC2 server as a final clean up operation. + +> :warning: Be warned! If the build fails or is cancelled midway through, the +> server instance is not automatically cleaned up! Later I intend to add a +> playbook to help do manual clean ups but until then you should keep an eye on +> the usage billing of your account to avoid any nasty surprises. + +To build with AWS, [you need an existing account][1] and you need to [generate +an access key or security token][2] and [configure your shell environment][3] +as needed (such as setting environment variables like below). + +``` +export AWS_ACCESS_KEY_ID="xxx" +export AWS_SECRET_ACCESS_KEY="yyy" +``` + +In addition to having [Ansible installed][4], you must also install the [boto3 +pypi package][5] and the [amazon.aws Ansible module][6]. This enables the +playbooks to interact with the AWS EC2 API. + +``` +pip install boto3 +ansible-galaxy collection install amazon.aws +``` + +You need to have an [SSH key pair already provisioned in your AWS account][7] +and configure the config.yaml accordingly based on the name (see: +`aws_ec2_aarch64_ssh_key` and `aws_ec2_x86_64_ssh_key`). The private key should +be configured for default use with your ssh client. + +## Usage + +You can run a build with AWS EC2 by invoking `ansible-playbook` on the +`aws-ec2.yaml` playbook with the aws\_ec2 inventory. + +``` +ansible-playbook -i inventories/aws-ec2/aws_ec2.yaml aws-ec2.yaml +``` + +The results of the build (on success) can be found in the `out` directory +(created in the current working directory). See the [Outputs section](#Output-Directory) +below for more details on the output contents. + +[1]: https://docs.aws.amazon.com/accounts/latest/reference/manage-acct-creating.html +[2]: https://repost.aws/knowledge-center/create-access-key +[3]: https://docs.ansible.com/ansible/latest/collections/amazon/aws/docsite/guide_aws.html#authentication +[4]: https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html#installing-and-upgrading-ansible +[5]: https://boto3.amazonaws.com/v1/documentation/api/latest/index.html +[6]: https://docs.ansible.com/ansible/latest/collections/amazon/aws/docsite/guide_aws.html +[7]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-key-pairs.html diff --git a/inventories/aws-ec2/aws_ec2.yaml b/inventories/aws-ec2/aws_ec2.yaml new file mode 100644 index 0000000..0cf378c --- /dev/null +++ b/inventories/aws-ec2/aws_ec2.yaml @@ -0,0 +1,8 @@ +plugin: amazon.aws.aws_ec2 +hostnames: + - tag:Name +filters: + tag:asz: + - "1" +compose: + ansible_host: public_ip_address diff --git a/roles/aws-ec2-instantiate/tasks/instantiate_builder.yaml b/roles/aws-ec2-instantiate/tasks/instantiate_builder.yaml new file mode 100644 index 0000000..9d392ec --- /dev/null +++ b/roles/aws-ec2-instantiate/tasks/instantiate_builder.yaml @@ -0,0 +1,30 @@ +--- +- name: Create a security group for ssh access to builder instances + amazon.aws.ec2_security_group: + name: "asz-security-group-ssh" + description: security group for ssh access to asz builders + region: "{{ aws_ec2_aarch64_region if target_arch == 'aarch64' else aws_ec2_x86_64_region }}" + rules: + - proto: tcp + ports: + - 22 + cidr_ip: 0.0.0.0/0 + rule_desc: allow all on port 22 + state: present + +- name: Create a basic ec2 instance with ssh key + amazon.aws.ec2_instance: + name: "asz-server-{{ server_id }}" + key_name: "{{ aws_ec2_aarch64_ssh_key if target_arch == 'aarch64' else aws_ec2_x86_64_ssh_key }}" + instance_type: "{{ aws_ec2_aarch64_instance_type if target_arch == 'aarch64' else aws_ec2_x86_64_instance_type }}" + image_id: "{{ aws_ec2_aarch64_ami if target_arch == 'aarch64' else aws_ec2_x86_64_ami }}" + region: "{{ aws_ec2_aarch64_region if target_arch == 'aarch64' else aws_ec2_x86_64_region }}" + network: + assign_public_ip: true + delete_on_termination: true + security_groups: + - "asz-security-group-ssh" + tags: + asz: "1" + state: running + wait: true diff --git a/roles/aws-ec2-instantiate/tasks/main.yaml b/roles/aws-ec2-instantiate/tasks/main.yaml new file mode 100644 index 0000000..7d26810 --- /dev/null +++ b/roles/aws-ec2-instantiate/tasks/main.yaml @@ -0,0 +1,35 @@ +--- +- name: load variables + ansible.builtin.include_vars: ../../../config.yaml + +# Prepare server id +- name: prepare random server id + ansible.builtin.set_fact: + server_id: "{{ lookup('community.general.random_string', length=4, special=false) }}" + +- name: debug server id + ansible.builtin.debug: + msg: "server id: {{ server_id }}" + +# Instantiate ec2 instance +- include_tasks: instantiate_builder.yaml + +- meta: refresh_inventory + +- name: prepare ansible hosts group for playbook usage + ansible.builtin.add_host: + name: "asz-server-{{ server_id }}" + groups: "asz_server" + +- name: debug ansible host ip + ansible.builtin.debug: + msg: "{{ hostvars['asz-server-'+server_id].public_ip_address }}" + +- name: wait_for_connection + ansible.builtin.wait_for: + port: 22 + host: "{{ hostvars['asz-server-'+server_id].public_ip_address }}" + delay: 30 + connect_timeout: 60 + timeout: 300 + remote_user: ec2-user diff --git a/roles/aws-ec2-teardown/tasks/main.yaml b/roles/aws-ec2-teardown/tasks/main.yaml new file mode 100644 index 0000000..6d2625e --- /dev/null +++ b/roles/aws-ec2-teardown/tasks/main.yaml @@ -0,0 +1,6 @@ +--- +- name: load variables + ansible.builtin.include_vars: ../../../config.yaml + +# Teardown the hetzner server +- include_tasks: teardown_builder.yaml diff --git a/roles/aws-ec2-teardown/tasks/teardown_builder.yaml b/roles/aws-ec2-teardown/tasks/teardown_builder.yaml new file mode 100644 index 0000000..31cba2b --- /dev/null +++ b/roles/aws-ec2-teardown/tasks/teardown_builder.yaml @@ -0,0 +1,7 @@ +--- +- name: Ensure the server is absent (remove if needed) + amazon.aws.ec2_instance: + state: absent + region: "{{ aws_ec2_aarch64_region if target_arch == 'aarch64' else aws_ec2_x86_64_region }}" + instance_ids: + - "{{ hostvars['asz-server-'+server_id].instance_id }}"