So I'm trying to setup my Gitlab CI to trigger a job on git push to build and deploy my Docker. This is the .gitlab-ci.yml file I'm using based on an example from Gitlab docs (Elixir yml).
stages:
- build
build:
before_script:
- docker build -f Dockerfile.build -t ci-project-build-$CI_PROJECT_ID:$CI_BUILD_REF .
- docker create
-v /build/deps
-v /build/_build
-v /build/rel
-v /root/.cache/aceapp/
--name build_data_$CI_PROJECT_ID_$CI_BUILD_REF busybox /bin/true
tags:
- docker
stage: build
script:
- docker run --volumes-from build_data_$CI_PROJECT_ID_$CI_BUILD_REF --rm -t ci-project-build-$CI_PROJECT_ID:$CI_BUILD_REF
The output when pushing to GitLab instance is this:
Running with gitlab-runner 10.7.2 (b5e03c94)
on my.host.rhel.runner 8f724ea7
Using Shell executor...
Running on my.host.local...
Fetching changes...
HEAD is now at 14351c4 Merge branch 'Development' into 'master'
From https://my.host.example/zalmosc/ace-app
14351c4..9fa2d43 master -> origin/master
Checking out 9fa2d435 as master...
Skipping Git submodules setup
$ # Auto DevOps variables and functions # collapsed multi-line command
$ setup_docker
$ build
Logging to GitLab Container Registry with CI credentials...
Login Succeeded
Building Dockerfile-based application...
invalid argument "/master:9fa2d4358e6c426b882e2251aa5a49880013614b" for t: Error parsing reference: "/master:9fa2d4358e6c426b882e2251aa5a49880013614b" is not a valid repository/tag: invalid reference format
See 'docker build --help'.
ERROR: Job failed: exit status 1
I understand the docker tag is not valid (is the before_script: really triggered based on the name?), and I'm looking for help regarding a) a solution b) how I can learn more about the requirements for a pipeline that builds docker based on default settings. Do I need to tag my docker image locally and then somehow add this to my git commit?
The thing is -t is to tag your Docker image. See the docs here.
The tag should be formated like name:version, and you giving it /master:9fa2d4358e6c426b882e2251aa5a49880013614b which is not a valid tag. You could try to delete the / before master
Your tag cannot begin with '/':
$ docker build -f Dockerfile.build -t /master:9fa2d4358e6c426b882e2251aa5a49880013614b .
invalid argument "/master:9fa2d4358e6c426b882e2251aa5a49880013614b" for "-t, --tag" flag: invalid reference format
See 'docker build --help'.
# remove '/'
$ docker build -f Dockerfile.build -t master:9fa2d4358e6c426b882e2251aa5a49880013614b .
Sending build context to Docker daemon 3.584kB
Step 1/3 : FROM ubuntu:16.04
---> 14f60031763d
...
If you are not using the built in registry, you might have to set the CI_REGISTRY_IMAGE value to something. It seems that if you don't se this it gets set to /master and causes this error. you can set this in the CI setting page, or when making a new pipeline. e.g CI_REGISTRY_IMAGE gitlab.com/user/project
Related
Running Gitlab version 14.8.2, same version for the Runner, which is a simple shell.
This is my yaml ci file:
variables:
REPOSITORY: $CI_REGISTRY/acme/test/test-acme/master
before_script:
- export PATH=$PATH:/usr/local/go/bin
- docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY
build_image:
script:
- echo -e "machine gitlab.acme.com\nlogin gitlab-ci-token\npassword ${CI_JOB_TOKEN}" > $HOME/.netrc
- git config --global url."https://gitlab-ci-token:${CI_JOB_TOKEN}#gitlab.acme.com".insteadOf git#gitlab.acme.com
- go mod download
- go build
- docker build -f Dockerfile.A4B -t $REPOSITORY:latest .
- docker push $REPOSITORY:latest
This is the output:
Running with gitlab-runner 14.8.2 (c6e7e194)
on gitlab-runner-4 QxNeqEeQ
Preparing the "shell" executor 00:00
Using Shell executor...
Preparing environment 00:01
Running on gitlab-runner-4...
Getting source from Git repository 00:00
Fetching changes with git depth set to 50...
Reinitialized existing Git repository in /home/gitlab-runner/builds/QxNeqEeQ/0/acme/test/test-acme/.git/
Checking out aa26121e as master...
Removing test-acme
Skipping Git submodules setup
Executing "step_script" stage of the job script 00:02
$ export PATH=$PATH:/usr/local/go/bin
$ docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /home/gitlab-runner/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
$ echo -e "machine gitlab.acme.com\nlogin gitlab-ci-token\npassword ${CI_JOB_TOKEN}" > $HOME/.netrc
$ git config --global url."https://gitlab-ci-token:${CI_JOB_TOKEN}#gitlab.acme.com".insteadOf git#gitlab.acme.com
$ go mod download
$ go build
$ docker build -f Dockerfile.A4B -t $REPOSITORY:latest .
Step 1/8 : FROM registry.acme.com/acme/base/docker-go-runtime/master
Head "https://registry.acme.com/v2/acme/base/docker-go-runtime/master/manifests/latest": error parsing HTTP 403 response body: no error details found in HTTP response body: "{\"message\":\"access forbidden\",\"status\":\"error\",\"http_status\":403}"
Cleaning up project directory and file based variables 00:00
ERROR: Job failed: exit status 1
I can log in with no problem but once I try to build the image it seems I'm not authorized. The Dockerfile.A4B is this:
FROM registry.acme.com/acme/base/docker-go-runtime/master
....
If I do a pull like this it works just fine:
docker pull registry.acme.com:5050/acme/test/test-zip/master
UPDATE
I noticed that if I change my Dockerfile.A4B with this:
FROM registry.acme.com:5050/acme/base/docker-go-runtime/master
Instead of this:
FROM registry.acme.com/acme/base/docker-go-runtime/master
basically adding the port 5050 at the end it works.
So Iām wondering something wrong with the repository configuration?
Funny thing is that if I create a deploy Token and I login doing this:
docker login registry.acme.com -u gitlab+deploy-token-2 -p password
And I have full rights read and write, but when then I try to do a docker build like this it fails:
docker build -f Dockerfile.A4B -t registry.acme.com/acme/test/test-zip/master:latest .
Sending build context to Docker daemon 24.47MB
Step 1/8 : FROM registry.acme.com/acme/base/docker-go-runtime/master
error parsing HTTP 404 response body: unexpected end of JSON input: āā
which is slightly different
Trying to run a CLI command using a Pact image as part of Gitlab pipeline. However it is failing as Docker could not find the directory (target/pacts). Below are command and error details.
Command:
docker run pactfoundation/pact-cli:latest broker publish target/pacts --consumer-app-version=$CI_COMMIT_SHORT_SHA --tag=$CI_COMMIT_REF_NAME --broker-base-url=http://localhost:9090
Error:
Error making request - Errno::ENOENT No such file or directory # rb_sysopen - /target/pacts
/usr/lib/ruby/gems/2.7.0/gems/pact_broker-client-1.29.1/lib/pact_broker/client/pact_file.rb:32:in `read', attempt 1 of 3
As part of pipeline I have run ls target/pacts command just before docker command, and it shows that the directory exists.
I tried to map the the target directory using -v option as below but it still gives the same error.
Altered Command:
docker run -v $(pwd)/target:/target pactfoundation/pact-cli:latest broker publish /target/pacts --consumer-app-version=$CI_COMMIT_SHORT_SHA --tag=$CI_COMMIT_REF_NAME --broker-base-url=http://localhost:9090
Gitlab pipeline step
contract-publishing:
image: docker:latest
stage: contract-publish
tags:
- docker-privileged
before_script:
- export
- pwd
- ls -al
- ls target/pacts
script:
- >
docker run -v $(pwd)/target:/target pactfoundation/pact-cli:latest
broker publish /target/pacts
--consumer-app-version=$CI_COMMIT_SHORT_SHA
--tag=$CI_COMMIT_REF_NAME
--broker-base-url=http://localhost:9090
Please help.
It seems likely this is a docker related problem - the error is pretty clear. I'd take out the pact image and try something like this:
docker run -v $(pwd)/target:/target debian:latest ls /target/pacts
If that doesn't work, it might be that variable expansion or some other configuration in your gitlab setup is incorrect.
I am using CI pipelines on Gitlab to build docker images for deployment to Raspbian. Since my builds need to access some private NPM packages, I include in the Docker file the following line which creates a token file using the value stored in environment variable $NPM_TOKEN:
RUN echo //registry.npmjs.org/:_authToken=$NPM_TOKEN > ~/.npmrc
This works fine when building from my usual image (resin/raspberrypi3-node). However one of my containers is built from armhf/ubuntu. When the above line is executed, the build fails with the following error:
standard_init_linux.go:207: exec user process caused "no such file or directory"
The command '/bin/sh -c echo //registry.npmjs.org/:_authToken=$NPM_TOKEN >> ~/.npmrc' returned a non-zero code: 1
The build runs fine from docker build on my development machine (Windows 10) but not within the gitlab pipeline.
I have tried stripping down my docker and pipeline files to the bare minimum, and removed the environment variable and the tilde from the path, and this still fails for the ubuntu (but not the resin) image.
Dockerfile.test.ubuntu:
FROM armhf/ubuntu
RUN echo hello > world.txt
Dockerfile.test.resin:
FROM resin/raspberrypi3-node
RUN echo hello > world.txt
gitlab-ci.yml:
build_image:
image: docker:git
services:
- docker:dind
script:
- docker build -f Dockerfile.test.resin . # Succeeds
- docker build -f Dockerfile.test.ubuntu . # Fails
only:
- master
I have searched for similar issues and have seen this error reported when running a .sh file which contained CRLF combinations. Although I am developing on Windows, my IDE (VS Code) is set up to use LF, not CRLF and I have checked all the above files for compliance.
As in here, try and use double-quotes for your echo argument:
RUN echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > ~/.npmrc
And first, in your Dockerfile, do a RUN ls -alrth ~/ to check the accessibility/presence of the target folder.
That error was also reported in this thread (without any answer), with an example where the final version of the Dockerfile, as seen here, use this .gitlab-ci.yml.
The OP bighairdave confirms in the comments:
I copied the following from the example #VonC gave, and it worked:
variables:
DOCKER_HOST: "tcp://docker:2375"
DOCKER_DRIVER: overlay2
before_script:
- docker run --rm --privileged hypriot/qemu-register
I wonder how it would be possible to debug a Docker build by executing an intermediate build layer and run a debug container out of the layer to watch what is inside.
Because I found no answer anywhere, I created my custom solution, which works pretty well (see below).
Solution
I added a debug-failed-build job to my pipeline, which uploads the layer as docker image to a Gitlabs Docker registry:
.gitlab-registry-login: &local-registry-login
docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
build:
stage: build
script:
- *local-registry-login
- docker build --pull -t "${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG}" . | tee docker-build-debug.out
- docker push "${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG}"
artifacts:
paths:
- docker-build-debug.out
when: on_failure
expire_in: 30 mins
debug-failed-build:
stage: debug
script:
- *local-registry-login
- DEBUG_LAYER=$(grep '\-\-\-> [0-9a-z]' docker-build-debug.out |tail -1| cut -b 7-)
- docker tag "$DEBUG_LAYER" "${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG}-failed"
- docker push "${CI_REGISTRY_IMAGE}:${CI_COMMIT_REF_SLUG}-failed"
when: on_failure
dependencies:
- build
How it works
The output of the Docker build is stored in a file which in case of failure is passed as an artifact to the debug-failed-build job. Here is an example how the output of a Docker build could look like (just a snippet):
Step 16/19 : VOLUME ["/sys/fs/cgroup"]
---> Using cache
---> a63a68682fcb
Step 17/19 : COPY --from=ansibleci-base /ansibleci-base /ansibleci-base
---> Using cache
---> 98fa646b73fb
Step 18/19 : RUN ln -s /ansibleci-base/scripts/run-tests.sh /usr/local/bin/run-tests && ln -s /ansibleci-base/ansible-plugins/human_log.py /usr/local/lib/python3.6/dist-packages/ansible/plugins/callback/human_log.py
---> Running in 83116392053c
ln: failed to create symbolic link '/usr/local/lib/python3.6/dist-packages/ansible/plugins/callback/human_log.py': No such file or directory
The expression behind the DEBUG_LAYER=... script command will extract the last layer id from the Docker build output (98fa646b73fb). The next command will give this layer an image name ready to upload to the registry and the final command will upload that image.
As an alternative to uploading the image you can also save the layer as file (with docker save) and store the saved image as compressed tar archive. Then you define this archife as Gitlab CI Artifact which you can download to your computer and docker load it there.
I have a very simple config.yml:
version: 2
jobs:
build:
working_directory: ~/app
docker:
- image: circleci/node:8.4.0
steps:
- checkout
- run: node -e "console.log('Hello from NodeJS ' + process.version + '\!')"
- run: yarn
- setup_remote_docker
- run: docker build .
All it does: boot a node image, test if node is running, do a yarn install and a docker build.
My dockerfile is nothing special; it has a COPY and ENTRYPOINT.
When I run circleci build on my MacBook Air using Docker Native, I get the following error:
Got permission denied while trying to connect to the Docker daemon socket at unix://[...]
If I change the docker build . command to: sudo docker build ., everything works as planned, locally, with circleci build.
However, pushing this change to CircleCI will result in an error: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
So, to summarize: using sudo works, locally, but not on CircleCI itself. Not using sudo works on CircleCI, but not locally.
Is this something the CircleCI staff has to fix, or is there something I can do?
For reference, I have posted this question on the CircleCI forums as well.
I've created a workaround for myself.
In the very first step of the config.yml, I run this command:
if [[ $CIRCLE_SHELL_ENV == *"localbuild"* ]]; then
echo "This is a local build. Enabling sudo for docker"
echo sudo > ~/sudo
else
echo "This is not a local build. Disabling sudo for docker"
touch ~/sudo
fi
Afterwards, you can do this:
eval `cat ~/sudo` docker build .
Explanation:
The first snippet checks if the CircleCI-provided environment variable CIRCLE_SHELL_ENV contains localbuild. This is only true when running circleci build on your local machine.
If true, it creates a file called sudo with contents sudo in the home directory.
If false, it creates a file called sudo with NO contents in the home directory.
The second snippet opens the ~/sudo file, and executes it with the arguments you give afterwards. If the ~/sudo file contains "sudo", the command in this example will become sudo docker build ., if it doesn't contain anything, it will become docker build ., with a space before it, but that will be ignored.
This way, both the local (circleci build) builds and remote builds will work.
To iterate on the answer of Jeff Huijsmans,
an alternative version is to use a Bash variable for docker:
- run:
name: Set up docker
command: |
if [[ $CIRCLE_SHELL_ENV == *"localbuild"* ]]; then
echo "export docker='sudo docker'" >> $BASH_ENV
else
echo "export docker='docker'" >> $BASH_ENV
fi
Then you can use it in your config
- run:
name: Verify docker
command: $docker --version
You can see this in action in my test for my Dotfiles repository
Documentation about environment variables in CircleCi
You might also solve your issue by running the docker image as root. Specify user: root under the image parameter:
...
jobs:
build:
working_directory: ~/app
docker:
- image: circleci/node:8.4.0
user: root
steps:
- checkout
...
...