Collection of Packer templates used for various infrastructure layers.
To build a given template, one may use the make
implicit builder, like the
following for ci-stevonnie
:
make ci-stevonnie
or, with a specific builder:
make ci-stevonnie BUILDER=docker
or forget about the Makefile
and run with packer
directly:
packer build -only=docker <(bin/yml2json < ci-stevonnie.yml)
Most of the templates in here require some env vars. Take a look at
.example.env
for an example. Use of
autoenv is encouraged but not
required.
There are two primary types of templates present at the top level: those
intended for use as execution environment for jobs flowing through Travis CI,
and those used for various backend fun in the Travis CI infrastructure. The
former type all have the prefix ci-
, described in more detail below:
There are two primary types of stacks: those targeting Ubuntu 14.04 (trusty), and those targeting Ubuntu 16.04 (xenial) that run on GCE and Docker.
Take a peek at what's what:
make stacks-trusty
make stacks-xenial
There may be some subtle variations, but for the most part each stack is built via the following steps.
The generated files in ./tmp/git-meta/
are copied onto the provisioned machine
at /var/tmp/git-meta/
for later use by the ./packer-scripts/packer-env-dump
script.
A git-tracked file in ./packer-assets
is copied onto the provisioned machine
at /var/tmp/purge.txt
for later use by the ./packer-scripts/purge
script.
A git-tracked file in ./packer-assets
is copied onto the provisioned machine
at /var/tmp/packages.txt
for later use by both the
travis_packer_templates::default
recipe and the serverspec suites via
./cookbooks/lib/support.rb
.
The script at ./packer-scripts/packer-env-dump
creates a directory on the
provisioned machine at /.packer-env
which is intended to be in the envdir
format. Any environment variables
that match ^(PACKER|TRAVIS)
, and (if present) the files previously written to
/var/tmp/git-meta/
are copied or written into /.packer-env/
.
The script at ./packer-scripts/remove-default-users
will perform a best-effort
removal of users defined in ${DEFAULT_USERS}
(default vagrant ubuntu
). The
primary reasons for this are general tidyness and to try to free up uid 2000.
The script at ./packer-scripts/pre-chef-bootstrap
is responsible for ensuring
the provisioned machine has all necessary packages and users for the Chef
provisioning process. The steps executed include:
/var/run/sshd
dir existssshd: ALL: ALLOW
exists in /etc/hosts.allow
travis
usertravis
user password to travis
#includedir /etc/sudoers.d
exists in /etc/sudoers
/etc/sudoers.d
dir exists/etc/sudoers.d/travis
file exists with specific permissions/home/travis/.ssh
dir exists/home/travis/.ssh/authorized_keys
file exists/var/tmp/*_rsa.pub
to /home/travis/.ssh/authorized_keys
/home/travis/.ssh/authorized_keys
perms are 0600
/home/travis/bin
dir existsThe script at ./packer-scripts/clone-travis-cookbooks
is responsible for git clone
'ing travis-cookbooks
into /tmp/chef-stuff
on the provisioned machine. Optional env vars supported
by this script are:
TRAVIS_COOKBOOKS_BRANCH
- the branch specified during git clone
TRAVIS_COOKBOOKS_EDGE_BRANCH
- the default branch used if
TRAVIS_COOKBOOKS_BRANCH
is not definedTRAVIS_COOKBOOKS_URL
- the git clone remote (default
https://github.com/travis-ci/travis-cookbooks.git
)TRAVIS_COOKBOOKS_SHA
- a git tree-ish to which the clone will be checked
out if defined (default not set)Once the clone is complete, the clone directory is written to
/.packer-env/TRAVIS_COOKBOOKS_DIR
and the head sha is written to
/.packer-env/TRAVIS_COOKBOOKS_SHA
.
The chef-solo
provisioner will typically have no json data, but instead will
leave all attribute and effective run list definition to a single wrapper
cookbook located in ./cookbooks/
.
Each wrapper cookbook must contain at least a metadata.rb
and a
recipes/default.rb
. Typically, the attributes/default.rb
is defined and
contains all override attribute settings. The earliest version of Chef used by
either trusty or xenial stacks is 12.9
, which means that all cookbook
dependencies must be declared in metadata.rb
, a requirement that is also
enforced by the foodcritic
checks.
For example, the minimal trusty image "ci-stevonnie" has a wrapper cookbook at
./cookbooks/travis-ci_stevonnie
that looks like this:
cookbooks/travis_ci_stevonnie
├── README.md
├── attributes
│ └── default.rb
├── metadata.rb
├── recipes
│ └── default.rb
└── spec
├── ...
The script at ./packer-scripts/ensure-travis-user
is responsible for ensuring
the existence of the travis
user and its home directory permissions,
optionally setting the password to a random string. The list of operations is:
travis
user existstravis
user password/home/travis
exists/home/travis/.ssh/authorized_keys
and /home/travis/.ssh/known_hosts
both exist and have permissions of 0600
/home/travis/.ssh/authorized_keys
/home/travis
is fully owned by travis:travis
Optional env vars supported by this script are:
TRAVIS_USER_PASSWORD
- a string (default "travis")TRAVIS_OBFUSCATE_PASSWORD
- if non-empty, causes
TRAVIS_USER_PASSWORD
to be set to a random stringThe script at ./packer-scripts/purge
is responsible for purging packages that
are not desirable for the CI environment, such as the Chef that was installed
prior for the Chef provisioner. Additionally, any package names present in
/var/tmp/purge.txt
will be purged. Optional env vars supported by this script
are:
APT_GET_UPGRADE_DURING_CLEANUP
- if non-empty, triggers an apt-get -y upgrade
prior to package purging.CLEAN_DEV_PACKAGES
- if non-empty, purges any packages matching -dev$
The script at ./packer-scripts/disable-apparmor
is responsible for disabling
apparmor if detected. This is done primarily so that services such as
PostgreSQL and Docker may be used in the CI environment without first updating
apparmor configuration and restaring said services.
The script at ./packer-scripts/run-serverspecs
is responsible for running the
serverspec suites via the rspec executable that is part of the chefdk
package.
The list of operations is:
chefdk
packagesudo-bash
wrapper for use in some specstravis:travis
${SPEC_SUITES}
chefdk
packageOptional env vars supported by this script are:
PACKER_CHEF_PREFIX
- directory in which to find packer chef stuff (default
/tmp
)SPEC_RUNNER
- string used to wrap execution of rspec (default sudo -u travis HOME=/home/travis -- bash -lc
)SPEC_SUITES
- comma-delimited string of spec suites to run (default not set)SKIP_CHEFDK_REMOVAL
- if non-empty do not remove the chefdk
package and
APT sourceThe script at ./packer-scripts/cleanup
is responsible for removing files and
directories that are unnecessary for the CI environment or otherwise add
unnecessary mass to the mastered image. The list of operations is:
/var/lib/apt/lists/*
/var/lib/man-db
/home/travis/linux.iso
and /home/travis/shutdown.sh
/var/log
Optional env vars supported by this script are:
CLEANUP_APT_LISTS
- if non-empty, trigger removal of /var/lib/apt/lists/*
CLEANUP_MAN_DB
- if non-empty, trigger removal of /var/lib/man-db
The script at ./packer-scripts/minimize
is responsible for reducing the size
of the provisioned image by squeezing out all of the empty space into a
contiguous area using the same method as
bento.
The list of operations is:
0
if $PACKER_BUILDER_TYPE
is either googlecompute
or amazon-ebs
,
as minimizing like this is superfluous on those builders$PACKER_BUILDER_TYPE
is not docker
, turn off swap and zero out the swap
partition if available./EMPTY
until the disk is out of space/EMPTY
and run sync
vmware-toolbox-cmd
is available, run disk shrink operations for both
/
/boot
paths.The script at ./bin/job-board-register
is responsible for "registering" the
mastered image in a post-processing step by making an HTTP request to the
job-board images API. The list of
operations is:
^(PACKER|TRAVIS|TAGS|IMAGE_NAME)
TAGS
env var that will be used as the tags
HTTP request param.curl
and pipe the response
through jq
Required env vars for this script are:
JOB_BOARD_IMAGES_URL
- the URL including PATH_INFO
prefix to job-boardIMAGE_NAME
- the name of the image, typically the same as that used by the
target infrastructureOptional env vars supported by this script are:
PACKER_ENV_DIR
- path to the envdir containing packer-specific env vars,
default /.packer-env
TAGS
- initial value for tags set during job-board registrationGROUP
- value used in group
tag, default edge
if edge conditions match,
else dev
DIST
- value used in dist
tag, default either Linux release codename or OS
X product versionOS
- value used in os
tag, default lowercase value of uname
, mapped to
osx
on DarwinFor more info on the relationship between a given packer build artifact and job-board, see job-board details below.
The job-board application is
responsible for tracking stack image metadata and presenting a queryable API
that is used by the travis-worker API image
selector.
As described above, each stack image is registered with job-board along with a
group
, os
, dist
, and map of tags
. When travis-worker requests a stack
image identifier, it performs a series of queries with progressively lower
specificity.
Of the values assigned to each stack image, the tags
map is perhaps most
mysterious, in part because it is so loosely defined. This is intentional, as
the number of values that could be considered "tags" varies enough that
maintaining them all as individual columns would result in (opinions!) too much
overhead in the form of schema management and query complexity.
The implementation of the job-board-register
script includes a process that converts the
languages
and features
arrays present in /.job-board-register.yml
, written
from the values present in chef attributes at
travis_packer_templates.job_board.{features,languages}
, into "sets"
represented as {key} => true
. For example, if a given wrapper cookbook
contains attributes like this:
override['travis_packer_templates']['job_board']['languages'] = %w(
fribble
snurp
zzz
)
then the tags generated for registration with job-board would be equivalent to:
{
"language_fribble": true,
"language_snurp": true,
"language_zzz": true
}
A "tagset" is the "set" (as in the type) of the "tags" applied during job-board
registration of a particular stack image, including languages
and features
.
At the time of this writing, both tagsets are used during serverspec runs, and
only the languages
tagset is considered during selection via the job-board
API.
Because the travis-worker API image
selector
is querying job-board for stack images that match a particular language, it is
important for us to ensure reasonably consistent image selection by way of
asserting the languages
values do not overlap between certain stacks (an
"exclusive" relationship). Additionally, it is important that we ensure certain
stack features
are subsets of others (an "inclusive" relationship).
Part of the CI process for this repository makes assertions about such exclusive and inclusive relationships by way of the check-job-board-tags script. The exact relationships being enforced may be viewed like so:
./bin/check-job-board-tags --list-only
An exclusive tagset relationship is equivalent to asserting that the set intersection is the empty set, e.g.:
tagset_a = %w(a b c)
tagset_b = %w(d e f)
assert (tagset_a & tagset_b).empty?
An inclusive tagset relationship is equivalent to asserting that all members of one tagset are present in another, or that a tagset's intersection with its superset is equivalent to itself, e.g.:
tagset_a = %w(a b c d e f)
tagset_b = %w(f d b)
assert (tagset_a & tagset_b).sort == tagset_b.sort
When submitting changes to this repository, please be aware that the top level-specs are shallow and don't include logic changes in the cookbooks.
Any cookbook specs are ran as part of the actual image building
process, which is triggered when any of the ci-<image-name>.yml
templates are modified.
The image build is ran as part of the packer-build repo on the branch corresponding to each template and is triggered by travis-packer-build.
This can be installed and invoked locally by running bundle install
and then bundle exec travis-packer-build [options]
.
Example:
bundle exec travis-packer-build \
-I ci-sardonyx.yml \
--target-repo-slug="travis-infrastructure/packer-build" \
--github-api-token="<your-token-here>" \
--body-tmpl=".packer-build-pull-request-false-tmpl.yml"
You can specify the branch using -B
(if you don't want to build from master).
The file .packer-build-pull-request-false-tmpl.yml
here is just an
example, but you can also create a different template that specifies
other travis-cookbooks or packer-template branches.
Additionaly, if you just want to test a change in
travis-cookbooks, you
can use the shortcut script in ./bin/packer-build-cookbooks-branch
:
./bin/packer-build-cookbooks-branch <travis-cookbooks-branch-name> <template-name>
Note: The above script expects the GITHUB_API_TOKEN
environment variable to be set.
Once created, the images will be registered in job-board under the
group: dev
tag.