So, you’re a longtime consumer of CircleCI with tasks arrange and working like clockwork. However, one fantastic morning, it strikes you to modify to GitHub Actions. Why? Possibly you’d like to make use of fewer third get together providers and wish to hold your code and CI course of in a single place? Maybe you have already got a paid GitHub account with free GitHub Actions minutes simply mendacity round? A technique or one other, the choice has been made, and it’s time to determine what awaits us on the way in which from CircleCI to GitHub Actions.
On this article, we’ll reply these questions:
- Is it potential emigrate a Ruby on Rails or a Node.js undertaking from CircleCI to GitHub Actions with (nearly) no adjustments?
- What are the variations between CircleCI and GitHub Actions, and most significantly, how are they comparable?
- Is it’s potential to make the CI course of on GitHub Actions quicker than on CircleCI?
- Do we actually want containers for CI?
- How you can velocity up CI with Docker picture construct caching?
An summary of GitHub Actions
Earlier than continuing to the configuration, let’s take a basic have a look at GitHub Actions. As you may see from the overview, it’s similar to CircleCI. It has the identical workflows
, which encompass jobs
, which in flip are a sequence of a number of steps
.
steps
might be executed each within the Docker container and instantly on the runner’s OS. Every particular person step
might be both a daily shell command or an motion.
Actions are analogous to orbs
from CircleCI; they’re used for a similar function: to mix many operations underneath one roof and to simplify their reuse. For instance, the setup-node motion installs the specified model of Node.js, provides it to PATH
, and so forth.
Most actions are written in JavaScript, however this isn’t the one method to create them.
You possibly can even use a Docker picture as an motion! I’ll present an instance with this strategy on the finish of the article.
CircleCI setup
As a check case, I’ll be utilizing a web site primarily based on Ruby on Rails and Node.js. Our place to begin is the .circleci/config.yml
file:
model: 2.1
workflows:
model: 2
build-and-deploy:
jobs:
- checkout_code
- bundle_install:
requires:
- checkout_code
- yarn_install:
requires:
- checkout_code
- rubocop:
requires:
- bundle_install
- yarn_build:
requires:
- yarn_install
- check:
requires:
- bundle_install
- yarn_build
executors:
ruby:
docker:
- picture: cimg/ruby:2.7.0-node
surroundings:
BUNDLE_PATH: vendor/bundle
GEM_HOME: vendor/bundle
BUNDLE_JOBS: 3
BUNDLE_RETRY: 3
RAILS_ENV: check
rails:
docker:
- picture: cimg/ruby:2.7.0-node-browsers
surroundings:
BUNDLE_PATH: vendor/bundle
GEM_HOME: vendor/bundle
BUNDLE_JOBS: 3
BUNDLE_RETRY: 3
RAILS_ENV: check
INCLUDE_FIXTURES: true
DATABASE_URL: postgresql://root@localhost:5432/circle_test
FAIL_SCREEN: 1
- picture: cimg/postgres:9.6-alpine
surroundings:
POSTGRES_USER: root
POSTGRES_DB: circle_test
jobs:
checkout_code:
executor: ruby
steps:
- attach_workspace:
at: .
- checkout
- persist_to_workspace:
root: .
paths: .
bundle_install:
executor: ruby
steps:
- attach_workspace:
at: .
- restore_cache:
keys:
- bundle-{{ checksum "Gemfile.lock" }}
- run:
title: Configure Bundler
command: |
echo 'export BUNDLER_VERSION=$(cat Gemfile.lock | tail -1 | tr -d " ")' >> $BASH_ENV
supply $BASH_ENV
gem set up bundler
- run:
title: Bundle Set up
command: bundle examine || bundle set up
- save_cache:
key: bundle-{{ checksum "Gemfile.lock" }}
paths: vendor/bundle
- persist_to_workspace:
root: .
paths: vendor/bundle
yarn_install:
executor: ruby
steps:
- attach_workspace:
at: .
- restore_node_modules_cache
- run:
title: Yarn Set up
command: yarn set up --verbose
- save_node_modules_cache
yarn_build:
executor: ruby
steps:
- attach_workspace:
at: .
- restore_node_modules_cache
- restore_assets_cache
- run:
title: Yarn Construct
command: yarn construct --verbose
- save_assets_cache
rubocop:
executor: ruby
steps:
- attach_workspace:
at: .
- run:
title: Rubocop
command: |
bundle exec rubocop --fail-level E
check:
parallelism: 1
executor: rails
steps:
- attach_workspace:
at: .
- restore_node_modules_cache
- restore_assets_cache
- run:
title: Watch for database
command: dockerize -wait tcp://localhost:5432 -timeout 1m
- run:
title: Database setup
command: bundle exec rails db:check:put together
- run:
title: RSpec system checks
command: |
BUILT_ASSETS_AVAILABLE=1 bundle exec rspec
instructions:
restore_node_modules_cache:
description: Restore node_modules/
steps:
- restore_cache:
keys:
- v1-yarn-dependency-cache-{{ checksum "yarn.lock" }}
- v1-yarn-dependency-cache
save_node_modules_cache:
description: Save node_modules/
steps:
- save_cache:
key: v1-yarn-dependency-cache-{{ checksum "yarn.lock" }}
paths:
- node_modules
- ~/.cache/yarn
restore_assets_cache:
description: Restore property cache
steps:
- restore_cache:
keys:
- v1-property-cache-{{ .Department }}-{{ .Revision }}
- v1-property-cache-{{ .Department }}
- v1-property-cache
save_assets_cache:
description: Save compiled property
steps:
- save_cache:
key: v1-property-cache-{{ .Department }}-{{ .Revision }}
paths:
- public/entrance
All the pieces is as common right here: bundle
, yarn
, rspec
and rubocop
.
A couple of vital notes on the configuration above:
- In CircleCI there may be such a factor as an executor. There are 4 sorts that may be declared and configured:
docker
,machine
,macos
, orhome windows
. Later, for everyjob
, it’s ample to specifyexecutor: name-of-executor
to execute all subsequent steps utilizing it. This is a crucial observe as a result of GitHub Actions doesn’t use this strategy. In our CircleCI configuration, considered one of two executors is used for all steps:ruby
andrails
. We use the usual Docker photos supplied and maintained by CircleCI and configure them by passing in surroundings variables. - To keep away from doing a
checkout
originally of every step, we use thecheckout_code
job, which runsgit clone
as soon as and shops the contents of the repository within theworkspace
, which in flip is handed between the person steps. This accelerates the entireworkflow
, particularly if the repository may be very massive. - The
bundler
andyarn
dependencies, in addition to compiled property, are cached to hurry up rebuilds.
So, it’s time to show your current CircleCI config right into a GitHub Actions config, however how? Let’s go along with the simplest method: we’ll attempt to repeat the identical steps with minimal adjustments and see what occurs:
title: Launch workflow for Kuvaq
on:
push:
branches:
- important
jobs:
checkout_code:
runs-on: ubuntu-20.04
steps:
- makes use of: actions/checkout@v2
- title: Save repository's content material as artifact
makes use of: actions/add-artifact@v2
with:
title: repo
path: ${{ github.workspace }}
bundle_install:
runs-on: ubuntu-20.04
wants: checkout_code
container: cimg/ruby:2.7.0-node
env:
BUNDLE_PATH: vendor/bundle
GEM_HOME: vendor/bundle
BUNDLE_JOBS: 3
BUNDLE_RETRY: 3
RAILS_ENV: check
steps:
- title: Setup file system permissions
run: sudo chmod -R 777 $GITHUB_WORKSPACE /github /__w/_temp
- title: Get repository's content material
makes use of: actions/obtain-artifact@v2
with:
title: repo
- makes use of: actions/cache@v2
with:
path: vendor/bundle
key: bundle-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
bundle-${{ hashFiles('**/Gemfile.lock') }}
bundle-
- title: Bundle set up
run: |
gem set up bundler -v "$(cat Gemfile.lock | tail -1 | tr -d " ")"
bundle set up
yarn_install:
runs-on: ubuntu-20.04
wants: checkout_code
container: cimg/ruby:2.7.0-node
env:
BUNDLE_PATH: vendor/bundle
GEM_HOME: vendor/bundle
BUNDLE_JOBS: 3
BUNDLE_RETRY: 3
RAILS_ENV: check
steps:
- title: Setup file system permissions
run: sudo chmod -R 777 $GITHUB_WORKSPACE /github /__w/_temp
- title: Get repository's content material
makes use of: actions/obtain-artifact@v2
with:
title: repo
- makes use of: actions/cache@v2
with:
path: |
node_modules
~/.cache/yarn
key: v1-yarn-dependency-cache-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
v1-yarn-dependency-cache-${{ hashFiles('**/yarn.lock') }}
v1-yarn-dependency-cache-
- title: Yarn Set up
run: yarn set up --verbose
yarn_build:
runs-on: ubuntu-20.04
wants: yarn_install
container: cimg/ruby:2.7.0-node
env:
BUNDLE_PATH: vendor/bundle
GEM_HOME: vendor/bundle
BUNDLE_JOBS: 3
BUNDLE_RETRY: 3
RAILS_ENV: check
steps:
- title: Setup file system permissions
run: sudo chmod -R 777 $GITHUB_WORKSPACE /github /__w/_temp
- title: Get repository's content material
makes use of: actions/obtain-artifact@v2
with:
title: repo
- makes use of: actions/cache@v2
with:
path: |
node_modules
~/.cache/yarn
key: v1-yarn-dependency-cache-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
v1-yarn-dependency-cache-${{ hashFiles('**/yarn.lock') }}
v1-yarn-dependency-cache-
- makes use of: actions/cache@v2
with:
path: public/entrance
key: v1-property-cache-${{ github.ref }}-${{ github.sha }}
restore-keys: |
v1-assets-cache-${{ github.ref }}-${{ github.sha }}
v1-assets-cache-${{ github.ref }}
v1-assets-cache
- title: Yarn Construct
run: yarn construct --verbose
rubocop:
wants: bundle_install
runs-on: ubuntu-20.04
container: cimg/ruby:2.7.0-node
env:
BUNDLE_PATH: vendor/bundle
GEM_HOME: vendor/bundle
BUNDLE_JOBS: 3
BUNDLE_RETRY: 3
RAILS_ENV: check
steps:
- title: Setup file system permissions
run: sudo chmod -R 777 $GITHUB_WORKSPACE /github /__w/_temp
- title: Get repository's content material
makes use of: actions/obtain-artifact@v2
with:
title: repo
- makes use of: actions/cache@v2
with:
path: vendor/bundle
key: bundle-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
bundle-${{ hashFiles('**/Gemfile.lock') }}
bundle-
- title: Rubocop
run: bundle exec rubocop --fail-stage E
check:
wants:
- bundle_install
- yarn_build
runs-on: ubuntu-20.04
container: cimg/ruby:2.7.0-node-browsers
env:
BUNDLE_PATH: vendor/bundle
GEM_HOME: vendor/bundle
BUNDLE_JOBS: 3
BUNDLE_RETRY: 3
RAILS_ENV: check
INCLUDE_FIXTURES: true
DATABASE_URL: postgresql://root@postgres:5432/circle_test
FAIL_SCREEN: 1
BUILT_ASSETS_AVAILABLE: 1
providers:
postgres:
picture: cimg/postgres:9.6-alpine
env:
POSTGRES_USER: root
POSTGRES_DB: circle_test
choices: --well being-cmd pg_isready --well being-interval 10s --well being-timeout 5s --well being-retries 5
steps:
- title: Setup file system permissions
run: sudo chmod -R 777 $GITHUB_WORKSPACE /github /__w/_temp
- title: Get repository's content material
makes use of: actions/obtain-artifact@v2
with:
title: repo
- makes use of: actions/cache@v2
with:
path: vendor/bundle
key: bundle-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
bundle-${{ hashFiles('**/Gemfile.lock') }}
bundle-
- makes use of: actions/cache@v2
with:
path: |
node_modules
~/.cache/yarn
key: v1-yarn-dependency-cache-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
v1-yarn-dependency-cache-${{ hashFiles('**/yarn.lock') }}
v1-yarn-dependency-cache-
- makes use of: actions/cache@v2
with:
path: public/entrance
key: v1-property-cache-${{ github.ref }}-${{ github.sha }}
restore-keys: |
v1-assets-cache-${{ github.ref }}-${{ github.sha }}
v1-assets-cache-${{ github.ref }}
v1-assets-cache
- title: Setup database
run: bundle exec rails db:check:put together
- title: RSpec system checks
run: bundle exec rspec
The tip.
I hope you discovered this text helpful, and make sure you hold studying our weblog!
…okay, okay, let’s truly see what we did.
CircleCI and GitHub Actions: variations and similarities
We’ll undergo our new GitHub Actions configuration and attempt to suss out what’s much like CircleCI and what’s totally different. Let’s transfer from high to backside, and regularly, we’ll cope with every little thing as we encounter it.
Workflow → Job → Step
In CircleCI, the order during which jobs are executed and the dependencies between them are described within the workflows
block. There is no such thing as a such block in GitHub Actions. As a substitute, every job has a wants discipline that accepts an inventory of different job names that should full efficiently earlier than the present job can start executing.
Because of the lack of a workflow
block in GitHub Actions, the scenario is dealt with otherwise whenever you wish to run a selected job
whenever you decide to a selected department.
So, if in CircleCI, you have got one thing like this:
workflows:
model: 2
build-and-deploy:
jobs:
- . . .
- bundle_audit:
requires:
- bundle_install
filters:
branches:
solely: audit
- . . .
Then, in GitHub Actions, you’ll have to make use of the if
block on the “jobs” stage:
on:
push:
branches:
- important
jobs:
bundle_audit:
runs-on: ubuntu-20.04
wants: bundle_install
if: github.ref == 'refs/heads/audit'
steps:
persist_to_workspace
vs. upload-artifact
Let’s see how the checkout_code
job has modified.
The closest equal for the persist_to_workspace
and attach_workspace
pair from the GitHub Actions world are the upload-artifact
and download-artifact
actions.
Be aware that the GitHub Motion doesn’t use a particular checkout step to obtain code from the repository. As a substitute, the checkout motion is accountable for getting the code, which isn’t any totally different from different actions you will discover within the market.
The container
and env
fields
Now let’s check out the bundle_install
job.
As I mentioned earlier than, in GitHub Actions every step
is usually a shell command or an motion. An motion itself is usually a JavaScript program or a Docker container. Each shell instructions and actions of all types are executed instantly on the runner (if the job
description doesn’t have the container discipline). If current, all steps
are executed contained in the container that has been created from the required picture.
jobs:
job_name_here:
steps:
- title: This step will run by shell on runner OS
run: echo "Resort Menetekel"
- title: This step will run JavaScript code on runner OS
makes use of: actions/good day-world-javascript-motion@important
- title: This step will run separate container
makes use of: actions/good day-world-docker-motion@important
jobs:
job_name_here:
container: ruby:2.7
steps:
- title: This step will run by shell inside ruby container
run: echo "Resort Menetekel"
- title: This step will run JavaScript code inside ruby container
makes use of: actions/good day-world-javascript-motion@important
- title: This step will nonetheless run separate container, sure
makes use of: makes use of: actions/good day-world-docker-motion@important
An motion is usually a Docker picture and run as Docker container. The query instantly arises: what’s going to occur to actions of that sort? Will it’s docker-in-docker
? As you may see from above instance, no. Truly the container actions can be run as sibling containers on the identical community with the identical quantity mounts.
The env block specifies the surroundings variables that can be handed to every step
. These variables are the identical for all jobs aside from checkout_code
and check
. It might be handy to make use of YAML anchors to keep away from repetition, however sadly, they’re nonetheless not supported in Github Actions.
Now, let’s take a person have a look at among the steps
.
The CircleCI Docker photos nuisance
- title: Setup file system permissions
run: sudo chmod -R 777 $GITHUB_WORKSPACE /github /__w/_temp
This step provides full entry to the $GITHUB_WORKSPACE
, /github
and /__w/_temp
directories for any consumer. This can be a facet impact of utilizing CircleCI photos. Their Dockerfiles use the USER circleci
assertion, so the consumer within the container doesn’t have ample rights to entry these directories.
To exclude this step
, it’s essential to use Docker photos with out the USER
assertion. We use these photos as a result of we wish to replicate our CircleCI config as step one to our new GitHub Actions config.
Caching in GitHub Actions
- makes use of: actions/cache@v2
with:
path: vendor/bundle
key: bundle-${{ hashFiles('**/Gemfile.lock') }}
restore-keys: |
bundle-${{ hashFiles('**/Gemfile.lock') }}
bundle-
As with checkout
, caching in GitHub Actions is carried out by an motion, not by the reserved save_cache
and restore_cache
. actions/cache@v2
performs the save and restore in a single step. If a cache with the required secret’s discovered, then it’s linked and used within the present step. If a cache isn’t discovered, it is going to be created and saved in case of profitable completion of the job (not the present step, however your complete job).
Similar to in CircleCI, you may specify an inventory of keys by which the cache might be retrieved if no actual match is discovered.
providers
Block
Nicely, all attention-grabbing components of the bundle_install
job have now been examined. It is senseless to concentrate on the yarn_install
, yarn_build
and rubocop
jobs, as a result of they’re nearly the identical as bundle_install
.
Let’s transfer on to the check
job, which is barely totally different from what we’ve seen earlier than:
check:
container: cimg/ruby:2.7.0-node-browsers
env:
DATABASE_URL: postgresql://root@postgres:5432/circle_test
providers:
postgres:
picture: cimg/postgres:9.6-alpine
env:
POSTGRES_USER: root
POSTGRES_DB: circle_test
choices: --well being-cmd pg_isready --well being-interval 10s --well being-timeout 5s --well being-retries 5
In CircleCI, extra containers inside the identical job might be listed in an executor
declaration. All of the steps described within the job are carried out within the first of the listed containers and the remaining containers are linked to the identical community and can be found via localhost
.
GitHub Actions makes use of the container and providers fields for this function. The primary specifies the primary container and the second lists extra containers that can be wanted in the course of the execution of the job. For instance, in our case it’s a database.
Be aware that the worth of the DATABASE_URL
variable within the env
block has modified from postgresql://root@localhost:5432/circle_test
to postgresql://root@postgres:5432/circle_test
. Not like CircleCI, in GitHub Actions, extra containers will not be out there via localhost
, however by their names, that are specified within the providers
block when they’re created.
Testing the brand new Github Motion configuration
Nicely, we’ve completed discussing the configuration for GitHub Actions! Let’s examine what got here out of it. We’ll save the contents to the file asis.yml
and put it within the root of the repository alongside the trail .github/workflows/asis.yml
. Subsequent, we’ll invoke essentially the most well-known spell from The Commonplace Guide of Spells, which works one thing like this: git add - git commit - git push
. We then go to the Actions tab within the net interface of the GitHub repository.
Not one of the best outcome! The complete workflow
takes as a lot as 10 minutes, whereas on CircleCI, it solely takes about 4. Let’s strive to determine the stage the place we’re dropping a lot time. We’ll take the job bundle_install
for example.
You possibly can discover (and that is additionally seen in all different jobs) that the Get repository's content material
step, throughout which the artifact with the contents of the repository is downloaded, takes the longest time. Apparently, the upload-artifact - download-artifact
motion pair isn’t a superb alternative for the persist_to_workspace - attach_workspace
pair from CircleCI.
Let’s attempt to substitute this step in all jobs with actions/checkout@v2
. If you consider it, checkout
in GitHub Actions ought to be quicker than its CircleCI counterpart checkout_code
as a result of each the runner and the server that hosts the repository are more likely to be shut to one another from a community viewpoint, and it’s probably that the throughput between them can be very excessive.
Let’s check this concept and see the outcome.
Nicely, it is a good outcome!
We removed the checkout_code
job, and we added a primary step which downloads the contents of the repository utilizing actions/checkout@v2
to every job, thus lowering the time to five minutes.
Can we go even additional and velocity up the entire course of much more?
No extra containers
Let’s check out the execution statistics for every particular person job once more.
Have you ever observed which step is repeated in all jobs and takes rather more time than the remainder? Initialize containers
takes 30-50% of your complete job execution time! Most of that point is spent downloading large Docker photos on runner. For instance, the compressed picture circleci/ruby:2.7.0-node
is 508.82 MB and must be downloaded to finish nearly each job in our workflow.
A pure query emerges right here: is it actually essential to carry out all actions inside containers? Is there one other method to get an nearly equally repeatable surroundings, entry to the appropriate utilities on the execution stage of every particular person step, whereas on the identical time lowering the general preparation time?
There may be such a method, and I feel it can come as no shock that every one of this may be performed utilizing actions!
There are numerous actions, like setup-
, appropriate for each style: Ruby, Java, Go, Node.js, Python and so forth.
All of them carry out the identical operate: making ready the surroundings for the corresponding language. As a substitute of downloading an enormous Ruby container, you should use the motion ruby/setup-ruby@v1
and it’ll set up the specified model in seconds, add it to $PATH
, run bundle set up
and arrange gem caching!
We solely want a couple of strains of configuration:
- makes use of: ruby/setup-ruby@v1
with:
ruby-version: 2.7.0
bundler-cache: true
Equally, we add every little thing mandatory for Node.js:
- makes use of: actions/setup-node@v2
with:
node-version: '13'
cache: 'yarn'
After changing all containers with the corresponding actions, the ensuing workflow appears like this (spoiler alert):
---
title: Launch workflow for Kuvaq
on:
push:
branches:
- important
jobs:
bundle_install:
runs-on: ubuntu-20.04
env:
BUNDLE_PATH: vendor/bundle
GEM_HOME: vendor/bundle
BUNDLE_JOBS: 3
BUNDLE_RETRY: 3
RAILS_ENV: check
steps:
- makes use of: actions/checkout@v2
- makes use of: ruby/setup-ruby@v1
with:
ruby-version: 2.7.0
bundler-cache: true
yarn_install:
runs-on: ubuntu-20.04
steps:
- makes use of: actions/checkout@v2
- makes use of: actions/setup-node@v2
with:
node-version: '13'
cache: 'yarn'
- makes use of: actions/cache@v2
with:
path: |
node_modules
~/.cache/yarn
key: v1-yarn-dependency-cache-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
v1-yarn-dependency-cache-${{ hashFiles('**/yarn.lock') }}
v1-yarn-dependency-cache-
- title: Yarn Set up
run: yarn set up --verbose
yarn_build:
runs-on: ubuntu-20.04
wants: yarn_install
steps:
- makes use of: actions/checkout@v2
- makes use of: actions/setup-node@v2
with:
node-version: '13'
cache: 'yarn'
- makes use of: actions/cache@v2
with:
path: |
node_modules
~/.cache/yarn
key: v1-yarn-dependency-cache-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
v1-yarn-dependency-cache-${{ hashFiles('**/yarn.lock') }}
v1-yarn-dependency-cache-
- makes use of: actions/cache@v2
with:
path: public/entrance
key: v1-property-cache-${{ github.ref }}-${{ github.sha }}
restore-keys: |
v1-assets-cache-${{ github.ref }}-${{ github.sha }}
v1-assets-cache-${{ github.ref }}
v1-assets-cache
- title: Yarn Construct
run: yarn construct --verbose
rubocop:
wants: bundle_install
runs-on: ubuntu-20.04
env:
BUNDLE_PATH: vendor/bundle
GEM_HOME: vendor/bundle
BUNDLE_JOBS: 3
BUNDLE_RETRY: 3
RAILS_ENV: check
steps:
- makes use of: actions/checkout@v2
- makes use of: ruby/setup-ruby@v1
with:
ruby-version: 2.7.0
bundler-cache: true
- title: Rubocop
run: bundle exec rubocop --fail-stage E
check:
wants:
- bundle_install
- yarn_build
runs-on: ubuntu-20.04
env:
BUNDLE_PATH: vendor/bundle
GEM_HOME: vendor/bundle
BUNDLE_JOBS: 3
BUNDLE_RETRY: 3
RAILS_ENV: check
INCLUDE_FIXTURES: true
DATABASE_URL: postgresql://root:postgres@localhost:5432/circle_test
FAIL_SCREEN: 1
BUILT_ASSETS_AVAILABLE: 1
providers:
postgres:
picture: postgres:9.6-alpine
env:
POSTGRES_DB: circle_test
POSTGRES_USER: root
POSTGRES_PASSWORD: postgres
choices: --well being-cmd pg_isready --well being-interval 10s --well being-timeout 5s --well being-retries 5
ports:
- 5432:5432
steps:
- makes use of: actions/checkout@v2
- makes use of: ruby/setup-ruby@v1
with:
ruby-version: 2.7.0
bundler-cache: true
- makes use of: actions/setup-node@v2
with:
node-version: '13'
cache: 'yarn'
- makes use of: actions/cache@v2
with:
path: |
node_modules
~/.cache/yarn
key: v1-yarn-dependency-cache-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
v1-yarn-dependency-cache-${{ hashFiles('**/yarn.lock') }}
v1-yarn-dependency-cache-
- makes use of: actions/cache@v2
with:
path: public/entrance
key: v1-property-cache-${{ github.ref }}-${{ github.sha }}
restore-keys: |
v1-assets-cache-${{ github.ref }}-${{ github.sha }}
v1-assets-cache-${{ github.ref }}
v1-assets-cache
- title: Setup database
run: bundle exec rails db:check:put together
- title: RSpec system checks
run: bundle exec rspec
With that, let’s see if we managed to cut back the time of your complete workflow:
Now, it is a actually good outcome! We’ve not solely managed to succeed in the CircleCI time, however we’ve additionally considerably surpassed it!
After all, this result’s a consequence of the compromise we made once we deserted containers. On one hand, containers will let you obtain near 100% surroundings repeatability, however on the identical time, they tremendously gradual your complete CI course of.
Certain, utilizing actions doesn’t assure full repeatability (you haven’t any management over the state of the runner’s working system and the packages put in there), however in my view, there are lots of conditions the place this stage of repeatability is sufficient.
Take a detailed have a look at your CircleCI configuration whenever you switch it to GitHub Actions—maybe many steps don’t require containers and might be changed by current actions. Doing this, as we noticed from our instance, can considerably scale back the overall time of your complete workflow. And this implies dashing up the event course of and lowering your month-to-month invoice for GitHub Actions!
As a bonus for individuals who have learn this text to the top, I supply a small addition. It’s extremely probably that on the finish of the workflow, you’ll wish to construct a Docker picture along with your utility. It’s much more probably that you just’ll wish to do that on each commit, and most significantly, as shortly as potential.
A yr in the past, our weblog already had an article about caching when constructing docker photos in GitHub Actions, however since then, every little thing has turn out to be a lot simpler.
Let’s check out a job that builds and pushes the picture, after which we’ll cope with essentially the most attention-grabbing components:
build-and-push:
runs-on: ubuntu-20.04
steps:
- title: Try repository
makes use of: actions/checkout@v2
- title: Login to GAR
makes use of: docker/login-motion@v1
with:
registry: us-docker.pkg.dev
username: _json_key
password: ${{ secrets and techniques.GA_GCP_JSON_KEY }}
- title: Arrange Docker Buildx
makes use of: docker/setup-buildx-motion@v1
- title: Construct and push
makes use of: docker/construct-push-motion@v2
with:
context: ./
file: ./Dockerfile.k8s
build-args: |
RUBY_VERSION=2.7.0
PG_MAJOR=10
NODE_MAJOR=13
BUNDLER_VERSION=2.1.4
RAILS_ENV=improvement
NODE_ENV=improvement
push: true
tags: us-docker.pkg.dev/deponia/portafisco/kuvaq:${{ github.sha }}
cache-from: sort=gha
cache-to: sort=gha,mode=max
- title: Save Google credentials to file
run: echo "${GOOGLE_APPLICATION_CREDENTIALS}" > "${GITHUB_WORKSPACE}/ga_gcp_json_key.json"
env:
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets and techniques.GA_GCP_JSON_KEY }}
- title: Clear Google Artifact Registry
makes use of: docker://us-docker.pkg.dev/gcr-cleaner/gcr-cleaner/gcr-cleaner-cli@sha256:959419dd9402edd27f4116d95bb21a9ed6024adec8ea777588a2031a80b91df2
with:
args: >
-repo=us-docker.pkg.dev/deponia/portafisco/kuvaq
-grace=2160h
-keep=30
-allow-tagged=true
-dry-run=false
env:
GOOGLE_APPLICATION_CREDENTIALS: ${{ github.workspace }}/ga_gcp_json_key.json
As you may see within the Login to GAR
step, in our case, we’re utilizing the Google Artifact Registry as a spot to retailer our photos, however many different repositories are additionally supported.
The following step is making ready the Docker Buildx, however essentially the most attention-grabbing half occurs within the Construct and push
step.
Beforehand, caching required sort=native
and a separate step to avoid wasting and restore the cache from the non permanent listing, right now nonetheless, a easy sort=gha
within the cache-from
and cache-to
fields is sufficient!
Though this sort of cache remains to be within the experimental stage, it really works nice and has by no means triggered issues. If you wish to get extra confidence with this, you may discover the kind of cache that fits your wants, in addition to different choices right here.
Take note of the final step. Right here, the makes use of
discipline doesn’t specify an motion, however a common Docker picture, to which arguments and surroundings variables are handed. This whole step is an enormous alternative for the docker run ...
command. It makes use of the gcr-cleaner program, which removes previous photos that don’t meet the situations listed within the args
discipline. This can be a very helpful method of controlling the scale of a docker repository and maintaining it inside affordable limits.
Nicely, that almost wraps issues up. The journey from CircleCI to GitHub Actions was fairly a experience, however hopefully you discovered it to be comparatively turbulence free! And another factor: if in case you have an issue or undertaking in want: frontend, backend, SRE providers, cellular, blockchain, or ML—Evil Martians are prepared to assist! Give us a shout!