Using Build Arguments on Codeship Pro

Written by: Laura Frank Tacho
4 min read

Earlier today, Codeship announced support for build arguments on our Codeship Pro platform. You can read the announcement here.

Build arguments allow you to pass custom values to your Docker image during the image build process. Unlike environment variables, these values won’t be persisted to the build image, making them a great way to customize your image build process if you know that the variable isn’t needed at runtime. A few examples where build args come in handy are accessing private assets, like a private gem server, or passing in a path that may change from build to build.

Codeship Pro services use build arguments in the same way that Docker does; in fact, the arguments you provide are passed directly to Docker running on your build machine. If you’re interested in learning more about using build args with Docker specifically, you can read through their documentation. I’ll walk through an example using a service in a Codeship Pro build below.

Let’s say we want to pass a version number to the image as the variable VERSION. Since this changes with each commit to controller, we can’t hardcode it in the Dockerfile as an environment variable. Instead, we can use a build argument that will allow Docker to use the value when the image is built, but not persist it to the final build image (meaning we can’t access it at runtime).

To consume build arguments during a service’s build process, you must first update your Dockerfile. This essentially creates an unset variable, and lets Docker know that it should expect a value to be passed in at build time.

Note: To follow along with this example, you must download the latest version of the Codeship Jet CLI, which includes support for build arguments.

FROM ubuntu:16.04
# … brilliant dockerfile instructions ...
# echo the version number for educational purposes
# … brilliant dockerfile instructions ...

In the codeship-services.yml file, populate the value of VERSION by using a build argument.

    dockerfile: Dockerfile
      VERSION: ‘1.0’

We’ll also have a codeship-steps.yml file that simply prints all available environment variables:

- service: app
  command: printenv

Watch the image build output when running jet steps:

$ jet steps
{BuildImageStarted=image_name:"codeship_app" service_name:"app"}
{BuildImageStdout=image_name:"codeship_app" service_name:"app"}: Step 1/4 : FROM busybox
{BuildImageStdout=image_name:"codeship_app" service_name:"app"}:  ---> 1efc1d465fd6
{BuildImageStdout=image_name:"codeship_app" service_name:"app"}: Step 2/4 : ARG VERSION
{BuildImageStdout=image_name:"codeship_app" service_name:"app"}:  ---> Using cache
{BuildImageStdout=image_name:"codeship_app" service_name:"app"}:  ---> 12f013c537f5
{BuildImageStdout=image_name:"codeship_app" service_name:"app"}: Step 3/4 : RUN echo $VERSION
{BuildImageStdout=image_name:"codeship_app" service_name:"app"}:  ---> Running in 7c3495ae5386
{BuildImageStdout=image_name:"codeship_app" service_name:"app"}: 12345678
{BuildImageStdout=image_name:"codeship_app" service_name:"app"}:  ---> 4b521e8442e1
{BuildImageStdout=image_name:"codeship_app" service_name:"app"}: Removing intermediate container 7c3495ae5386
{BuildImageStdout=image_name:"codeship_app" service_name:"app"}: Step 4/4 : COPY . .
{BuildImageStdout=image_name:"codeship_app" service_name:"app"}:  ---> 0b26a0344df4
{BuildImageStdout=image_name:"codeship_app" service_name:"app"}: Removing intermediate container d0f6c374f790
{BuildImageStdout=image_name:"codeship_app" service_name:"app"}: Successfully built 0b26a0344df4
{BuildImageFinished=image_name:"codeship_app" service_name:"app"}

Then we see the output for printenv from our step command:

{ContainerRunStdout=step_name:"printenv" service_name:"app"}: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
CI_STRING_TIME=2017-01-04 19:29:55.597121241 +0000 UTC
no_proxy=*.local, 169.254/16
{StepFinished=step_name:"printenv" type:STEP_FINISHED_TYPE_SUCCESS}

The VERSION variable is missing, because build args aren’t available at runtime.

Build arguments can also helpful in the case that you want to access private assets during your image build. Because you don’t want these arguments in your repo in plain text, Codeship supports encrypted build arguments as well. To encrypt a file with build arguments, you’ll need to download the local Codeship Jet CLI and get your Codeship Pro project’s AES key from the Project Settings page.

Create a file called build_args.env. It might look something like this:


Take care to use KEY=value syntax instead of key: value in this file. Using the Jet CLI, encrypt the file.

jet encrypt build_args.env build_args.env.encrypted

Then, include that file in your build directive for the service that consumes it. Note that you still need to add the ARG instructions to your service’s Dockerfile in order to use the encrypted arguments.

    dockerfile: Dockerfile
    encrypted_args_file:  encrypted_args_file: build_args.encrypted 

Codeship will decrypt your build arguments and pass them to the image at buildtime as an unencrypted value.

Note: Docker advises against using build arguments to pass in any sort of secrets to your images, as they can be seen when inspecting the image layers. This is great advice for production environments, but during CI/CD with Codeship all your builds run in a single-tenant environment, and no other user or machine has access to your build machine. Your machine (and everything on it!) is also destroyed after each build, never being reused. Because of this, it is advised to use build arguments necessary for the CI/CD process on Codeship while being sure not to deploy images to production that use them in the same way.

Check out the documentation article on build arguments, our encryption guide, and an overview of handling secrets during Codeship Pro builds.

Have questions about Codeship Pro or build arguments? Ask a question on the Codeship community forum.

Stay up to date

We'll never share your email address and you can opt out at any time, we promise.