How to cache docker-compose build inside github-action - github

Is there any way to cache docker-compose so that it will not build again and again?
here is my action workflow file:
name: Github Action
on:
push:
branches:
- staging
jobs:
test:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout#v1
- name: Bootstrap app on Ubuntu
uses: actions/setup-node#v1
with:
node-version: '12'
- name: Install global packages
run: npm install -g yarn prisma
- name: Install project deps
if: steps.cache-yarn.outputs.cache-hit != 'true'
run: yarn
- name: Build docker-compose
run: docker-compose -f docker-compose.test.prisma.yml up --build -d
I want to cache the docker build step. I have tried using if: steps.cache-docker.outputs.cache-hit != 'true' then only build but didn't work.

What you are referring to is called "docker layer caching", and it is not yet natively supported in GitHub Actions.
This is discussed extensively in several places, like:
Cache docker image forum thread
Cache a Docker image built in workflow forum thread
Docker caching issue in actions/cache repository
As mentioned in the comments, there are some 3rd party actions that provide this functionality (like this one), but for such a core and fundamental feature, I would be cautious with anything that is not officially supported by GitHub itself.

For those arriving here via Google, this now "supported". Or at least it is working: https://github.community/t/use-docker-layer-caching-with-docker-compose-build-not-just-docker/156049.
The idea is to build the images using docker (and its cache) and then use docker compose to run (up) them.

If using docker/bake-action or docker/build-push-action & want to access a cached image in subsequent steps -
Use load:true to save the image
Use the same image name as the cached image across steps in order to skip rebuilds.
Example:
...
name: Build and push
uses: docker/bake-action#master
with:
push: false
load: true
set: |
web.cache-from=type=gha
web.cache-to=type=gha
-
name: Test via compose
command: docker compose run web tests
...
services:
web:
build:
context: .
image: username/imagename
command: echo "Test run successful!"
See the docker team's responses;
How to access the bake-action cached image in subsequent steps?
How to use this plugin for a docker-compose?
How to share layers with Docker Compose?`
Experiment on caching docker compose images in GitHub Actions

Related

Google Cloud, GitHub pipe with Google Cloud Run

I´m trying to a deploy pipe with Github and Google Cloud using cloud run cause´ i´m using docker containers in the server, this is my GitHub action code (workflow)
name: Build and Deploy to Cloud Run
on:
push:
branches:
- master
env:
PROJECT_ID: ${{ secrets.RUN_PROJECT }}
RUN_REGION: us-west2-a
SERVICE_NAME: helloworld-python
jobs:
setup-build-deploy:
name: Setup, Build, and Deploy
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout#v2
# Setup gcloud CLI
- name: Set up Python
uses: actions/setup-python#v4
with:
python-version: '3.9'
- uses: google-github-actions/setup-gcloud#v0
with:
version: '390.0.0'
service_account_email: ${{ secrets.ACC_MAIL }}
service_account_key: ${{ secrets.RUN_SA_KEY }}
project_id: ${{ secrets.RUN_PROJECT }}
# Build and push image to Google Container Registry
- name: Build
run: |-
gcloud builds submit \
--quiet \
--tag "gcr.io/$PROJECT_ID/$SERVICE_NAME:$GITHUB_SHA"
# Deploy image to Cloud Run
- name: Deploy
run: |-
gcloud run deploy "$SERVICE_NAME" \
--quiet \
--region "$RUN_REGION" \
--image "gcr.io/$PROJECT_ID/$SERVICE_NAME:$GITHUB_SHA" \
--platform "managed" \
--allow-unauthenticated
Everything seems to be "correct" but the moment I run the workflow, this error appears
ERROR: (gcloud.builds.submit) The required property [project] is not currently set.
You may set it for your current workspace by running:
$ gcloud config set project VALUE
or it can be set temporarily by the environment variable [CLOUDSDK_CORE_PROJECT]
The proyect ID is in the RUN_PROYECT secret, I don´t know what else to do
Is there any problem that is not letting the thing work?
Edited: Changing the version to 390.0.0 worked, but now I´m receiving this error
ERROR: (gcloud.builds.submit) Invalid value for [source]: Dockerfile required when specifying --tag
For the first error:
ERROR: (gcloud.builds.submit) The required property [project] is not currently set.
You may set it for your current workspace by running:
$ gcloud config set project VALUE
or it can be set temporarily by the environment variable [CLOUDSDK_CORE_PROJECT]
the gcloud command has not been properly configured.
According to the Authorization section of google-github-actions/setup-gcloud:
This action installs the Cloud SDK (gcloud). To configure its authentication to Google Cloud, use the google-github-actions/auth action.
So, you need to configure it for authorization using any one of the supported methods there.
For your second error:
ERROR: (gcloud.builds.submit) Invalid value for [source]: Dockerfile required when specifying --tag
the /path/to/Dockerfile is missing. You need to specify it in gcloud builds submit command.
See this relevant SO thread for more details:
Specify Dockerfile for gcloud build submit

CircleCI cannot find Serverless Framework after serverless installation

I'm trying to use Serverless Compose to deploy multiple services to AWS via CircleCI. I have 3 test services for a POC, and so far deploying these to a personal AWS account from the terminal works just fine. However, when I configure it to go through CircleCI with a config.yml file, I get this error:
Could not find the Serverless Framework CLI installation. Ensure Serverless Framework is installed before continuing.
I'm puzzled because my config.yml file looks like this:
version: 2.1
orbs:
aws-cli: circleci/aws-cli#3.1.1
serverless-framework: circleci/serverless-framework#2.0.0
node: circleci/node#5.0.2
jobs:
deploy:
parameters:
stage:
type: string
executor: serverless-framework/default
steps:
- checkout
- aws-cli/install
- serverless-framework/setup
- run:
command: serverless config credentials --provider aws --key $AWS_ACCESS_KEY_ID --secret $AWS_SECRET_ACCESS_KEY
name: Configure serverless
- run:
command: npm install #serverless/compose
name: Install #serverless/compose
- run:
command: serverless deploy --stage << parameters.stage >>
name: Deploy staging
workflows:
deploy-staging:
jobs:
- node/test:
version: 17.3.0
- deploy:
context: aws-*******-developers
name: ******-sandbox-use1
stage: staging
The serverless framework is set up, the orb is present, but it says that it could not be found. All steps are successful until I get to deploy staging. I've been digging through documentation but I can't seem to find where it's going wrong with CircleCI. Does anyone know what I may be missing?
Turns out this required a weird fix, but it's best to remove the following:
The orb serverless-framework: circleci/serverless-framework#2.0.0
The setup step in the job - serverless-framework/setup
The Configure Serverless step
Once these are removed, modify the Install #serverless/compose step to run npm install and install all the packages. Then run npx serverless deploy instead of serverless deploy. This fixed the problem for me.

How do I set the build output platform x86_64 in a Skaffold configuration?

Since I'm developing on an M1 mac, my Docker builds will build ARM. I want to build x86_64 images which I know I can build with the --platform flag but I want to do that with my Skaffold configuration.
Thanks to #p10l putting me on the right track, I was able to figure it out. Skaffold can't set the platform using the Docker Engine API, so we need to pass --platform=linux/x86_64 to the command line by setting useDockerCLI to true and adding cliFlags to our Docker configuration.
apiVersion: skaffold/v2beta26
kind: Config
build:
# ... other unrelated config ...
artifacts:
- image: my-image
context: ./
docker:
cliFlags:
- --platform=linux/x86_64
local:
useDockerCLI: true # the only way to set platform is with cliFlags so we need to enable the Docker CLI
Whoever is coming here from google and confront this problem, skaffold almost finished developing multi-arch support but as the version of v1.39.1, you can use
skaffold run --platform linux/amd64
or simply to configure it in skaffold.yaml file
Skaffold has buildCommand field to which you can pass a custom script.
So, for example
...
build:
artifacts:
- image: "foo"
context: .
custom:
buildCommand: ./build.sh
...
build.sh
docker buildx build \
--platform linux/amd64
... # any other flags
Disclaimer: Everything below is a speculation. I'm currently unable to test this, but I'm sure someone will correct me if I'm wrong.
There is also build.artifacts.docker field (currently in beta). It may be possible to use this field to pass arguments to Docker build.
...
build:
artifacts:
- image: "foo"
context: .
docker:
dockerfile: <Dockerfile relative to workspace>
target: <Dockerfile target name to build>
buildArgs:
platform: linux/amd64
local:
useDockerCLI: true #this is needed to use docker build CLI rather than Docker Engine API
It may also be required to set buildx as a default builder for Docker. This can be achieved with
docker buildx install

Gcloud build trigger environment variable substitution in app.yaml for appEngine

I am trying to substitue variable in app.yaml with a cloud build trigger.
I Added substitution variable in build trigger.
Add environment variables to app.yaml in a way they can be easily substituted with build trigger variables. Like this:
env_variables:
SECRET_KEY: %SECRET_KEY%
Add a step in cloudbuild.yaml to substitute all %XXX% variables inside app.yaml with their values from build trigger.
steps:
- name: node:10.15.1
entrypoint: npm
args: ["install"]
- name: 'gcr.io/cloud-builders/gcloud'
entrypoint: bash
args:
- '-c'
- |
sed -i 's/%SESSION_SECRET%/'${_SESSION_SECRET}'/g' app.yaml
timeout: "1600s"
The problem is that Gcloud Build throw an exception :
Already have image (with digest): gcr.io/cloud-builders/gcloud
bash: _L/g: No such file or directory
Why ? How can I make a substitution of my app.yaml ?
I have a app.yaml to the root of the project at the same level of the cloudbuild.yaml
UPDATED
I am trying to build and debug gcloud locally with this command:
sudo cloud-build-local --config=cloudbuild.yaml --write-workspace=../workspace --dryrun=false --substitutions=_SESSION_SECRET=test --push .
When I take a look into the app.yaml file, the substitution worked as expected and there is no exception at all.
What is the difference with the gcloud build environment ?
OK I finally decided to use github action instead of google cloud triggers.
Since Google cloud triggers aren't able to find its own app.yaml and manage the freaking environment variable by itself.
Here is how to do it:
My environment :
App engine,
standard (not flex),
Nodejs Express application,
a PostgreSQL CloudSql
First the setup :
1. Create a new Google Cloud Project (or select an existing project).
2. Initialize your App Engine app with your project.
[Create a Google Cloud service account][sa] or select an existing one.
3. Add the the following Cloud IAM roles to your service account:
App Engine Admin - allows for the creation of new App Engine apps
Service Account User - required to deploy to App Engine as service account
Storage Admin - allows upload of source code
Cloud Build Editor - allows building of source code
[Download a JSON service account key][create-key] for the service account.
4. Add the following [secrets to your repository's secrets][gh-secret]:
GCP_PROJECT: Google Cloud project ID
GCP_SA_KEY: the downloaded service account key
The app.yaml
runtime: nodejs14
env: standard
env_variables:
SESSION_SECRET: $SESSION_SECRET
beta_settings:
cloud_sql_instances: SQL_INSTANCE
Then the github action
name: Build and Deploy to GKE
on: push
env:
PROJECT_ID: ${{ secrets.GKE_PROJECT }}
DATABASE_URL: ${{ secrets.DATABASE_URL}}
jobs:
setup-build-publish-deploy:
name: Setup, Build, Publish, and Deploy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
- uses: actions/setup-node#v2
with:
node-version: '12'
- run: npm install
- uses: actions/checkout#v1
- uses: ikuanyshbekov/app-yaml-env-compiler#v1.0
env:
SESSION_SECRET: ${{ secrets.SESSION_SECRET }}
- shell: bash
run: |
sed -i 's/SQL_INSTANCE/'${{secrets.DATABASE_URL}}'/g' app.yaml
- uses: actions-hub/gcloud#master
env:
PROJECT_ID: ${{ secrets.GKE_PROJECT }}
APPLICATION_CREDENTIALS: ${{ secrets.GCLOUD_AUTH }}
CLOUDSDK_CORE_DISABLE_PROMPTS: 1
with:
args: app deploy app.yaml
To add secrets into git hub action you must go to : Settings/secrets
Take note that I could handle all the substitution with the bash script. So I would not depend on the github project "ikuanyshbekov/app-yaml-env-compiler#v1.0"
It's a shame that GAE doesn't offer an easiest way to handle environment variable for the app.yaml. I don't want to use KMS since I need to update the beta-settings/cloud sql instance.. I really needed to substitute everything into the app.yaml.
This way I can make a specific action for the right environment and manage the secrets.
The entrypoint should be an executable, use /bin/bash or /bin/sh.
How to inspect inside the image (in general):
$ docker pull gcr.io/cloud-builders/gcloud
Using default tag: latest
latest: Pulling from cloud-builders/gcloud
...
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
gcr.io/cloud-builders/gcloud latest 8499764c4ef6 About an hour ago 4.01GB
$ docker run -ti --entrypoint '/bin/bash' 8499764c4ef6
root#60354dfb588a:/#
You can test your commands from there to test without having to sending it to Cloud Build each time.

Docker Compose bind mount doesn't work in GitHub Actions

If I run a Docker Compose command in GitHub Actions which uses a bind mount, it says the source directory doesn't exist. Here's the error.
Cannot create container for service chat: invalid mount config for type "bind": bind source path does not exist: /__w/omni-chat/omni-chat
I think the issue is that the root directory is incorrectly being passed to GitHub Actions. I specified the absolute path as the conventional ., but I don't know what caveats GitHub Actions has regarding that.
Here's a simplified version of my workflow.
on: push
jobs:
test-server:
runs-on: ubuntu-latest
container: docker/compose
steps:
- uses: actions/checkout#v2
- run: docker-compose run --rm chat gradle test
Here's a simplified version of my Docker Compose file.
version: '3.7'
services:
chat:
image: gradle:6.3-jdk8
command: bash
volumes:
- type: bind
source: .
target: /home/gradle
- type: volume
source: gradle-cache
target: /home/gradle/.gradle
volumes:
gradle-cache:
If you need the full details, here's the exact run.
It turns out that you should use preinstalled Docker Compose installation. So simply removing the specified container will allow bind mounts to work since it's no longer a Docker-in-Docker scenario.