Building FreeBSD ports for a variety of servers and clients takes
a lot of computational resources. Since mine are sparse, using the cloud
for building is attractive. This repository provides a skeleton for
creating a temporary poudriere build machine running as an EC2
instance on Amazon AWS. The machine is created with the help of
Terraform and multiple sh scripts.
The approach offers some outstanding characteristics: The skeleton is split into two layers: one for permanent, and one for temporary cloud infrastructure -- storage and build machine respectively. While building, poudriere's state is saved on an EBS. When building is completed, the packages are stored on a S3 bucket. In sum, this offers two huge advantages:
-
Since poudriere's state is on an EBS, created ports trees, jails and packages are stored independently from the build machine itself. Thus, you can deploy a very powerful machine in the cloud, use and pay it only as long as you really need it, and destroy it afterwards. The next time you want to compile packages, simply deploy a new instance -- it will re-attach the EBS and already created ports trees, jails, and packages are at hand.
-
Serving the bucket as static website, the packages can be made available for any FreeBSD machine easily.
The idea was inspired by JoergFiedler/freebsd-build-machine using
Vagrant, its AWS Provider, and Ansible. I prefer my
approach because Terraform, on the contrary to Vagrant, was originally
built for the cloud. Additionally, no knowledge of Ansible is necessary to
understand what is actually happening: despite Terraform's configuration
files everything is sh. This is up for discussion and I'm happy for any
suggested improvement.
Some tasks the skeleton cannot handle for you automagically yet. The following is a list of things you must take care of manually.
-
You must subscribe to Amazon AWS and have your "Access Key" and "Secret Key" at hand.
-
If you don't have one, create a SSH keyfile that is not password-protected (with its corresponding public key
insecure-keyfile.pub) e.g.,ssh-keygen -t rsa -b 4096 -N '' -f ~/.ssh/insecure-keyfile. Remember where you put that file. -
You need some basic understanding of Terraform and poudriere. While this skeleton automates a lot, it is not as user-friendly as it should be. So you should be aware of sharp edges.
-
Install Terraform from the official download page. Place it somewhere in your
$PATHto ease execution.Note: Because of a bug, I highly recommend using
terraformversion 0.8.8 (not the newer 0.9.x branch). -
Clone this repository to some place of your liking.
cdinto the directory of the repository. -
Copy
terraform.tfvars.exampletoterraform.tfvarsand open the latter. Adjust the variables accordingly i.e.,-
s3_bucket_nameis the name of the bucket where the build machine stores the compiled packages. Later you will access these packages from there. -
ssh_keyis the private part of your insecure keyfile i.e., in the case above it would be~/.ssh/insecure-keyfile. Terraform will upload its public part to AWS and associate it with the build machine. -
build_trees,build_jails, andbuild_setsare special as they need the most time configuring. Here you start deciding how and which packagespoudriereshall build for you.In the example given,
poudrierewill create a ports tree named "default". Further it will create a jail with methodsvn+https, call it "11armv6", create it according to thearm.armv6architecture, and base it onrelease/11.0.1. As you can see, you supply download method, name, architecture, and release separated by_. Last but not least,poudriereassumes a set called "default".In these variables you can specify multiple entries each separated by space. The build script will iterate through all of them.
-
-
Obviously, you must also tell
poudrierewhich packages to build. You do so by listing their portname in package lists that you create inuploads/pkglists. The name of each list must correspond to thebuild_trees,build_jails, andbuild_setsthat you configured interraform.tfvars. E.g.,uploads/pkglists/default-11armv6-defaultcontains packages for the ports tree named "default", the jail "11armv6", and set "default".As mentioned previously, the build script will iterate through all combinations of
build_trees,build_jails, andbuild_sets. However, it will not build anything, if there does not exist apkglistthat fits to a combination provided. -
Configuring what to build exactly is a bit difficult. Nevertheless, this makes it possible to build a variety of different package sets and preserves the versatility of
poudriere. Especially custom options, port blacklists, custompoudriere.conf,make.confandsrc.conffiles can all be set as documented inpoudriere(8). The correspondingpoudriere.ddirectory you can find inuploads/poudriere.d. -
As you might have already noticed, the skeleton consists of two parts:
1-storageand2-build-machine. Each of these is, according to Terraform's principles, one "layer". The structure makes it possible to deploy a consistent, permanent and an inconsistent, temporary part of infrastructure in the cloud. The first part creates an EBS and a S3 bucket. The EBS will be used for storing a ZFS pool that comprises poudriere's data output (created ports trees, jails, packages, etc.). The S3 bucket is used to store the package repository and poudriere's configuration.Thus, when configuration is all set you
cd 1-storageand runterraform apply. You will be asked about the size of the EBS. The size highly depends on the amount of ports trees, jails, and packages you plan to set-up.-
If you want to import an already existing bucket that has a folder structure as required by this script, you can do so by executing
terraform import aws_s3_bucket.packages <bucket-name>within1-storage. This will import the bucket into terraform's current state. -
The same works for an EBS volume, in case you already created one but lost your terraform state. Execute
terraform import aws_ebs_volume.poudriere <vol-id>in1-storage.
Next, you
cd ../2-build-machineand runterraform applyto create the build machine. You will be asked to specify the instance type. This mainly depends on the amount of money and time you want to spend. For testing, it makes sense to use ant2.microinstance.-
You can find an overview of available instances (and there corresponding key) at Amazon EC2 Instance Types. I recommend general purpose instances such as M4.
-
AWS Simple Monthly Calculator can help you to get an idea how much usage might cost.
-
-
Once the infrastructure was deployed, run
./init-sshto connect to the machine. -
Your're now on the remote machine. Start
tmuxand runsudo build-ports(it is important to run this command as root). This will start the build process (as complicated as you configured it). Depending on the amount of jails and packages that are created, this will take a while. When the build process itself is finished, the packages and poudriere's configuration are uploaded to the S3 bucket. -
When you're done, run
sudo zpool export tankon the remote side. This will release the attached EBS drive. If you don't, the builder cannot be destroyed with the next command. -
Don't forget to run
terraform destroywithin2-build-machine. Otherwise your Amazon AWS bill will rise. Do not destroy the first layer (1-storage) because it holds both the EBS and S3 bucket. -
Let your FreeBSD clients'
pkgknow about the S3 bucket. They can find packages underhttp://<s3_bucket_URL>/pkg.
The next time you want to compile packages, you don't need to re-create
the 1-storage layer. Only run terraform apply on the second layer
2-build-machine. When doing so, terraform will re-attach the EBS, the
build machine will mount the ZFS pool, and compilation can continue where
it stopped the last time.
builder.tfis the most important file. It includes the rules forterraformon how to create the infrastructure.init-sshis automatically created by terraform when deploying the infrastructure. It includes a simplesshcommand that lets you connect to the correct instance.templatesincludes several template files that are converted according to your configuration/use case when deploying the infrastructure.- The file created from
init.tplis passed to the build machine before it actually starts. It configures the machine to install some packages during boot time (as configured inbuilder.tfand sets upsudofor the userec2-user. - The script
build-ports.tplis used to build the ports. It will be created according to the ports trees, jails, and sets you defined invariables.tf. - The file created from
shrc.tplsets up environment variables for the userec2-user. This makes interaction with the S3 storage easier. - The script created from
upload-to-s3is used to upload the compiled packages to S3.
- The file created from
uploadsincludes several scripts and configuration files that are needed remotely to build the ports properly.ports/<tree-name>can include ports that have not been uploaded to the official ports tree yet. According to the name of the directory, these will be added to the to one of the trees configured by you and created by the builder.poudriere.confis the configuration file for poudriere.poudriere.dincludes further configuration for poudriere.
- hashicorp/terraform#13423 : Too many SSH connection attempts result in huge disk usage (at least for me)