Useful tips and best practices when migrating to CircleCI 2.0

We’re drawing closer to the end of 1.0. If you haven’t started the migration to 2.0 yet take a look through some of the tips and best practices aggregated below.

We’ll continue to update this list with any new info we can find. If you have any info you think would help others as they migrate feel free to share them below and we can update the list. Thanks to @rohara for getting this list started!

Remember August 31st, 2018 is the last day for 1.0. You need to make sure all of your projects are converted if you’d like them to continue building on CircleCI. You can read more about 1.0 end of life and find other helpful resources on our sunsetting 1.0 page.


You can build the same project on both CircleCI 1.0 and 2.0!

When starting to migrate to CircleCI 2.0 you don’t have to go all in straight away. Keep your project building on 1.0 and try 2.0 by do this:

  • create a new branch for testing 2.0
  • remove circle.yml from that branch and add a .circleci/config.yml file
  • write some minimal 2.0 config on that branch and push it until you get a green build
  • we recommend doing a little bit of config at a time so you can get feel for how it works - initially, just check out the code, then try installing dependencies, then try running your tests. Later you can start working out how to cache dependencies and use more advanced features like Workflows. Build up your config bit by bit.
  • when you have everything working you can merge the branch with the new config into your main project.

CircleCI specific

  • Commands listed in the steps can only be run in the first container listed in the docker section.
  • Run builds frequently to test the config thus far. If something breaks, you know what changed since the last build.
  • Don’t add workflows initially; wait until you have a functional build.
  • Build a config manually from scratch, but use the config-translation endpoint as a reference
  • You can’t define env vars with env vars in the environment section of the config
    • The workaround is to echo the vars into $BASH_ENV
      • This only works with bash, not sh (Alpine images only have sh)
  • Conditionally run commands with bash if statements
    • if [ $CIRCLE_BRANCH = “master” ] ; then ./ci.sh ; fi
  • Conditionally halt the build at that step with circleci step halt
    • Allows you to use setup_remote_docker conditionally by halting
  • The Timezone can be changed just by defining an env var
    • TZ: “/usr/share/zoneinfo/America/New_York”
  • Running the build out of /dev/shm (ie., /dev/shm/project) can speed up certain projects
    • Some things like Ruby gems can’t be loaded out of shared memory. They can be installed elsewhere in the system (~/vendor) and symlinked in.
  • Instead of prefixing a lot of commands with sudo, consider setting the shell to sudo for that run
    • shell: sudo bash -eo pipefail
  • Docker builds and docker-compose should generally be run in the machine unless language-specific tools (Ruby, Node, PHP, etc.) are required beforehand, then the remote environment is sufficient.
  • Some tasks can be set to run in the background to save overall build time, but be careful of running out of resources
  • Different resource_class sizes can be beneficial and it’s worth trying them to see their impact. It could have no impact at all.
  • The $PATH can be set to a string. If you don’t know your Docker image’s $PATH, just run it and echo $PATH or take a look at the output of env.
  • The sha of an image can be referenced under the Spin up Environment step. An image can be hardcoded to that sha value to make it immutable.
  • Service containers can be run with custom flags
    • command: [mysqld, --character-set-server=utf8mb4, --collation-server=utf8mb4_unicode_ci, --init-connect=‘SET NAMES utf8mb4;’]
  • Configure your test runners to only spawn two threads/wokers (or more if you’re using resource_class) when running in CI. Sometimes they will opotmize themselves based on incorrect values. Check out this video with more info.

Onboarding from 1 -> 2 specific

  • Note that $CIRCLE_ARTIFACTS and $CIRCLE_TEST_REPORTS are not defined in 2.0
    • You can define them yourself, but be sure to mkdir -p $CIRCLE_ARTIFACTS $CIRCLE_TEST_REPORTS if you do.
  • Migrating Linux & macOS in one repository (like React Native) should involve opening one branch for each Linux & macOS before combining the two configs into one workflow.
  • You can’t sudo echo - pipe it like this: echo "192.168.44.44 git.example.com" | sudo tee -a /etc/hosts
  • Fonts are different between Ubuntu and Debian systems.
  • Apache 2.2 and 2.4 configs are fairly different - make sure to upgrade your 2.2 configs.
  • Don’t forget all the commands inferred automatically by 1.0 and commands manually stored in the UI

Language specific

Python

  • Typically expects classnames and not filenames to run tests

Ruby

  • Ruby files can load in a different order than expected on AUFS
  • Define $RAILS_ENV and $RACK_ENV as test (this was automatic in 1.0)

Java(-based)

  • Java (apps, tools, and services) will OOM (run out of memory) because it doesn’t recognize how much RAM is available. An environment variable should be defined. If it’s still OOMing, a bigger container is necessary.
  • Scala projects can have filenames that are too long, include the -Xmax-classfile-name flag.
    • [Scala] sbt assembly does not work
      scalacOptions ++= Seq(
      “-encoding”, “utf-8”,
      “-target:jvm-1.8”,
      “-deprecation”,
      “-unchecked”,
      “-Xlint”,
      “-feature”,
      “-Xmax-classfile-name”, “242” <= add here
      ),

Browser testing

  • Tests can sometimes be flaky and fail for seemingly no reason. Some people opt to re-run their failing browser tests automatically. The drawback is corrupting the timing data.
  • Take screenshots of failed tests to make debugging easier
  • VNC can be installed & used. The browser can be dragged around in VNC after installing metacity. Run this from one of our browsers images:
    ssh -p PORT ubuntu@IP_ADDRESS -L 5902:localhost:5901 # To connect via SSH
    sudo apt install vnc4server metacity
    vnc4server -geometry 1280x1024 -depth 24
    export DISPLAY=:1.0
    metacity &
    firefox &

Docker specific

  • Build a Docker image on a cron job
    • Build weekly, daily, or whenever you need
      • Possible to trigger a new Docker image build via the API easily
    • Include dependencies like node_modules in the image
      • Helps mitigate issues from a DNS outage
      • Keeps the dependencies version controlled
      • Even if a module disappears from node’s repos, the necessary depenencies to run the application are safe.
    • A private image can include private gems and private source cache
  • There is no socket file for databases so the host variables need to be defined ($PGHOST, $MYSQL_HOST) to specify 127.0.0.1, forcing TCP
  • Using CircleCI convenience or official Docker Hub images increases the chance of having your image cached on the host
    • Building off these images will reduce the number of image layers that need to be downloaded
  • Using the -ram variation of a container will run the given daemon in /dev/shm
  • Building custom images with everything pre-installed speeds up the build and adds reliability
    • Heroku (as an example) could push a bad update to their installer, breaking your builds
  • The dockerize utility can be used to wait for service containers to be available before running tests
  • ElasticSearch has their own Docker registry from which to pull
  • Containers can have names so multiple of a given service can run on the same port with different hostnames
  • Privileged containers can be run in the remote environment and the machine
  • Volumes can’t be mounted from the base Docker executor into the remote environment
    • docker cp can transfer files
    • Volumes referenced will be mounted from the within the remote environment into the container

Fun facts:

  • You are limited by your imagination in CircleCI 2.0
  • The shell can be set to Python to just execute arbitrary Python in the YAML
			- run:
				shell: /usr/bin/python3
				command:
					import sys
					print(sys.version)
  • You can be clever with bash to achieve whatever you need
    for i in {1..5}; do curl -v $ENDPOINT_URL && break || sleep 10; done
2 Likes

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.