Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build an AMI #4

Merged
merged 8 commits into from
May 4, 2018
Merged

Build an AMI #4

merged 8 commits into from
May 4, 2018

Conversation

jcf
Copy link
Contributor

@jcf jcf commented Apr 11, 2018

The AMI now includes Clojure and common Clojure tooling (i.e. Boot and
Leiningen).

Support for both CodeDeploy and CloudFront are included (although not configured
or enabled out of the box), and packages from the AUR can be pulled down and
cached in a local repo.

Tasks

  • Test CodeDeploy starts up on EC2
  • Make sure log output reaches CloudWatch (need to create a log group and the associated config)
  • Make sure CodeDeploy isn't logging to a file Write CodeDeploy logs to journald #7

The AMI now includes Clojure and common Clojure tooling (i.e. Boot and
Leiningen).

Support for both CodeDeploy and CloudFront are included (although not configured
or enabled out of the box), and packages from the AUR can be pulled down and
cached in a local repo.
@jcf jcf self-assigned this Apr 11, 2018
@jcf
Copy link
Contributor Author

jcf commented Apr 11, 2018

I'd consider using something like Ansible to provision these changes in future. Doing everything with a set of Bash scripts is already a little painful, and will only get worse as complexity increases.

arch.json Outdated
@@ -1,35 +1,63 @@
{
"variables": {},
"_comment": "Keys prefixed with an underscore are comments.",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I don't have any comments I could remove this, but maybe it'll help someone down the line.

# Default: put built package and cached source in build directory
#
#-- Destination: specify a fixed directory where all packages will be placed
PKGDEST=/var/cache/pacman/juxt
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is in here so I can point makepkg at the new Pacman cache dir where local PKGBUILD and anything from AUR will end up.

You can query packages not in 'core' Arch repos like so:

pacman -Sl juxt

# %wheel ALL=(ALL) ALL

## Same thing without a password
%wheel ALL=(ALL) NOPASSWD: ALL
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passwordless sudo so we can install things more easily during deployment. Getting makepkg to work as the rock user when it asks to sudo things is not straightforward.

# Rock user

# Group for running pacman commands without needing to enter a password.
groupadd build
Copy link
Contributor Author

@jcf jcf Apr 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Build group can go as I'm no longer using it.

install_pkgs \
jq \
pacutils \
repose
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

repose is on the way out and people are moving to repoctl I'm told. Something to look out for in the not too distant future.

# We skip the PGP check because we won't have AladW's GPG key at this point.
#
# TODO Pull in GPG key and use it to check package.
su --preserve-environment -c 'makepkg --skippgpcheck' rock
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skipping PGP checks is me being lazy. It's the one package, but we could import AladW's key and do this right perhaps?

systemd-cloud-watch

# To install any packages from the AUR can now be done like so:
# aursync <pkg0> <pkg1> <pkg2> ...
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment isn't clear enough. You still have to get Pacman to put the package contents in the right place. This only installs in as much as it builds the package and adds it to your Pacman cache and the JUXT package repo.

all: $(DIRS)

$(DIRS): force
cd $@ && makepkg --printsrcinfo > .SRCINFO
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Easier than escaping the redirect in the shell script that does the provisioning.

user_data = "${data.template_file.user_data.rendered}"

# This needs to be created manually.
key_name = "rock"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've created this key in the JUXT AWS account, and can share it with you, @malcolmsparks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sent your way.

terraform plan -out proposed.plan

apply:
terraform apply proposed.plan
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plan looks reasonable, but I don't want to apply this anywhere near customer data etc.

@malcolmsparks do you have somewhere I can test this out tomorrow? If I can get an example user data script that configures things and starts up the services I think this work will be more or less done.

terraform fmt
terraform plan -out proposed.plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

data.template_file.user_data: Refreshing state...
data.aws_ami.rock: Refreshing state...

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  + aws_instance.rock
      id:                                        <computed>
      ami:                                       "ami-cec09ab7"
      associate_public_ip_address:               <computed>
      availability_zone:                         "eu-west-1"
      ebs_block_device.#:                        <computed>
      ephemeral_block_device.#:                  <computed>
      get_password_data:                         "false"
      instance_state:                            <computed>
      instance_type:                             "t2.small"
      ipv6_address_count:                        <computed>
      ipv6_addresses.#:                          <computed>
      key_name:                                  "rock"
      network_interface.#:                       <computed>
      network_interface_id:                      <computed>
      password_data:                             <computed>
      placement_group:                           <computed>
      primary_network_interface_id:              <computed>
      private_dns:                               <computed>
      private_ip:                                <computed>
      public_dns:                                <computed>
      public_ip:                                 <computed>
      root_block_device.#:                       "1"
      root_block_device.0.delete_on_termination: "true"
      root_block_device.0.volume_id:             <computed>
      root_block_device.0.volume_size:           "20"
      root_block_device.0.volume_type:           <computed>
      security_groups.#:                         <computed>
      source_dest_check:                         "true"
      subnet_id:                                 <computed>
      tags.%:                                    "2"
      tags.Name:                                 "rock"
      tags.Source:                               "juxt/rock"
      tenancy:                                   <computed>
      user_data:                                 "8aed11c63960f4590c9cdd426593ecba98c4ab69"
      volume_tags.%:                             <computed>
      vpc_security_group_ids.#:                  <computed>

  + aws_security_group.allow_all
      id:                                        <computed>
      arn:                                       <computed>
      description:                               "Allow all inbound traffic."
      egress.#:                                  <computed>
      ingress.#:                                 "1"
      ingress.482069346.cidr_blocks.#:           "1"
      ingress.482069346.cidr_blocks.0:           "0.0.0.0/0"
      ingress.482069346.description:             ""
      ingress.482069346.from_port:               "0"
      ingress.482069346.ipv6_cidr_blocks.#:      "0"
      ingress.482069346.protocol:                "-1"
      ingress.482069346.security_groups.#:       "0"
      ingress.482069346.self:                    "false"
      ingress.482069346.to_port:                 "0"
      name:                                      "allow_all"
      owner_id:                                  <computed>
      revoke_rules_on_delete:                    "false"
      tags.%:                                    "2"
      tags.Name:                                 "allow_all"
      tags.Source:                               "juxt/rock"
      vpc_id:                                    <computed>


Plan: 2 to add, 0 to change, 0 to destroy.

------------------------------------------------------------------------

This plan was saved to: proposed.plan

To perform exactly these actions, run the following command to apply:
    terraform apply "proposed.plan"

EOF

systemctl daemon-reload
systemctl start systemd-cloud-watch
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only logging for now. I've got to look at CodeDeploy once I've got journald forwarding nicely.

name = "name"

# Maybe we should rename the AMI to `juxt-rock`?
values = ["juxt-arch-*"]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I should rename the AMIs to juxt-rock-*?

I used Arch because I was thinking about splitting the AMIs in two; one for a more-or-less empty Arch AMI with up-to-date everything and a custom repo for AUR packages, and one for the Clojure stuff we want installed…

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've completed the rename in 30be5f7.

jcf added 2 commits April 12, 2018 16:07
As an alternative to the somewhat broken Go client this script is being used in
production and as such we know it works.

It isn't in any accessible version control so I've vendored it inside the
package.
This prevents potential conflicts and permission issues.
@jcf
Copy link
Contributor Author

jcf commented Apr 12, 2018

I've added the Bash script used elsewhere in production to push journald logs over to CloudWatch, and packaged it up.

It's installed in the AMI I'm building presently (ami-bafcd9c3), and has an associated systemd unit file that you can activate like so:

systemctl start journald-cloud-watch-script

Internally that runs the provided Bash script, which can be found in /usr/bin/tail-journald.

I haven't had time to test out the script so can't say for sure it will work if you provision an EC2 instance via the included Terraform configuration, which can be done like so:

cd terraform
make plan
# Review the output to make sure it's correct.
make apply

Note, Terraform state is only stored locally, although pushing state to S3 is relatively straightforward should you wish to do so. I've destroyed everything via make destroy.

HTH!

@jcf jcf changed the title Install Clojure dependencies via a private local repo Build an AMI Apr 12, 2018
"source_ami": "ami-0b8ec472",
"instance_type": "t2.small",
"ssh_username": "root",
"ami_name": "juxt-rock-{{user `commit_ref`}}-{{timestamp}}"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make the AMI public you need to add "ami_groups": ["all"].

# Install
install_pkgs \
codedeploy-agent \
journald-cloud-watch-script \
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the Bash script that will forward logs as an alternative to the Go project that doesn't seem to work.


INSTANCE_ID="${INSTANCE_ID:-$(curl -s http://169.254.169.254/latest/meta-data/instance-id)}"
AWS_REGION="${AWS_REGION:-$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone)}"
LOG_GROUP_NAME="${LOG_GROUP_NAME:-rock}"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These env vars could be set in an environment file via user data, perhaps?

# Looks like there's a but that results in a lot of log output from this library.
#
# Fix is in this PR: https://github.com/advantageous/systemd-cloud-watch/pull/16
# systemctl start systemd-cloud-watch
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the user data file that will be executed inside the EC2 instance when you provision with Terraform.

Starting services, adding configuration files goes here.

@malcolmsparks malcolmsparks merged commit af50d58 into master May 4, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants