在. gitlab-ci. yml 中运行 docker-compose build

我有一个 .gitlab-ci.yml文件,其中包含以下内容:

image: docker:latest


services:
- docker:dind


before_script:
- docker info
- docker-compose --version


buildJob:
stage: build
tags:
- docker
script:
- docker-compose build

但在 ci-log中,我收到了一条信息:

$ docker-compose --version
/bin/sh: eval: line 46: docker-compose: not found

我做错了什么?

118832 次浏览

EDIT I added another answer providing a minimal example for a .gitlab-ci.yml configuration supporting docker-compose.


docker-compose can be installed as a Python package, which is not shipped with your image. The image you chose does not even provide an installation of Python:

$ docker run --rm -it docker sh
/ # find / -iname "python"
/ #

Looking for Python gives an empty result. So you have to choose a different image, which fits to your needs and ideally has docker-compose installed or you maually create one.

The docker image you chose uses Alpine Linux. You can use it as a base for your own image or try a different one first if you are not familiar with Alpine Linux.

I had the same issue and created a Dockerfile in a public GitHub repository and connected it with my Docker Hub account and chose an automated build to build my image on each push to the GitHub repository. Then you can easily access your own images with the GitLab CI.

If you don't want to provide a custom docker image with docker-compose preinstalled, you can get it working by installing Python during build time. With Python installed you can finally install docker-compose ready for spinning up your containers.

image: docker:latest


services:
- docker:dind


before_script:
- apk add --update python py-pip python-dev && pip install docker-compose # install docker-compose
- docker version
- docker-compose version


test:
cache:
paths:
- vendor/
script:
- docker-compose up -d
- docker-compose exec -T php-fpm composer install --prefer-dist
- docker-compose exec -T php-fpm vendor/bin/phpunit --coverage-text --colors=never --whitelist src/ tests/

Use docker-compose exec with -T if you receive this or a similar error:

$ docker-compose exec php-fpm composer install --prefer-dist
Traceback (most recent call last):
File "/usr/bin/docker-compose", line 9, in <module>
load_entry_point('docker-compose==1.8.1', 'console_scripts', 'docker-compose')()
File "/usr/lib/python2.7/site-packages/compose/cli/main.py", line 62, in main
command()
File "/usr/lib/python2.7/site-packages/compose/cli/main.py", line 114, in perform_command
handler(command, command_options)
File "/usr/lib/python2.7/site-packages/compose/cli/main.py", line 442, in exec_command
pty.start()
File "/usr/lib/python2.7/site-packages/dockerpty/pty.py", line 338, in start
io.set_blocking(pump, flag)
File "/usr/lib/python2.7/site-packages/dockerpty/io.py", line 32, in set_blocking
old_flag = fcntl.fcntl(fd, fcntl.F_GETFL)
ValueError: file descriptor cannot be a negative integer (-1)
ERROR: Build failed: exit code 1

I created a simple docker container which has docker-compose installed on top of docker:latest. See https://hub.docker.com/r/tmaier/docker-compose/

Your .gitlab-ci.yml file would look like this:

image: tmaier/docker-compose:latest


services:
- docker:dind


before_script:
- docker info
- docker-compose --version


buildJob:
stage: build
tags:
- docker
script:
- docker-compose build

Following the official documentation:

# .gitlab-ci.yml
image: docker
services:
- docker:dind
build:
script:
- apk add --no-cache docker-compose
- docker-compose up -d

Sample docker-compose.yml:

version: "3.7"
services:
foo:
image: alpine
command: sleep 3
bar:
image: alpine
command: sleep 3

We personally do not follow this flow anymore, because you loose control about the running containers and they might end up running endless. This is because of the docker-in-docker executor. We developed a python-script as a workaround to kill all old containers in our CI, which can be found here. But I do not suggest to start containers like this anymore.

Docker also provides an official image: docker/compose

This is the ideal solution if you don't want to install it every pipeline.

Note that in the latest version of GitLab CI/Docker you will likely need to give privileged access to your GitLab CI Runner and configure/disable TLS. See Use docker-in-docker workflow with Docker executor

variables:
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2


# Official docker compose image.
image:
name: docker/compose:latest


services:
- docker:dind


before_script:
- docker version
- docker-compose version


build:
stage: build
script:
- docker-compose down
- docker-compose build
- docker-compose up tester-image

Note that in versions of docker-compose earlier than 1.25:

Since the image uses docker-compose-entrypoint.sh as entrypoint you'll need to override it back to /bin/sh -c in your .gitlab-ci.yml. Otherwise your pipeline will fail with No such command: sh

    image:
name: docker/compose:latest
entrypoint: ["/bin/sh", "-c"]

Alpine linux now has a docker-compose package in their "edge" branch, so you can install it this way in .gitlab-ci.yml


a-job-with-docker-compose:
image: docker
services:
- docker:dind
script:
- apk add docker-compose --update-cache --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ --allow-untrusted
- docker-compose -v

I think most of the above are helpful, however i needed to collectively apply them to solve this problem, below is the script which worked for me

I hope it works for you too

Also note, in your docker compose this is the format you have to provide for the image name

<registry base url>/<username>/<repo name>/<image name>:<tag>

image:
name: docker/compose:latest
entrypoint: ["/bin/sh", "-c"]


variables:
DOCKER_HOST: tcp://docker:2375/
DOCKER_DRIVER: overlay2


services:
- docker:dind


stages:
- build_images


before_script:
- docker version
- docker-compose version
- docker login -u $CI_REGISTRY_USER -p $CI_JOB_TOKEN $CI_REGISTRY


build:
stage: build_images
script:
- docker-compose down
- docker-compose build
- docker-compose push

It really took me some time to get it working with Gitlab.com shared runners.

I'd like to say "use docker/compose:latest and that's it", but unfortunately I was not able to make it working, I was getting Cannot connect to the Docker daemon at tcp://docker:2375/. Is the docker daemon running? error even when all the env variables were set.

Neither I like an option to install five thousands of dependencies to install docker-compose via pip.

Fortunately, for the recent Alpine versions (3.10+) there is docker-compose package in Alpine repository. It means that @n2o's answer can be simplified to:

test:
image: docker:19.03.0


variables:
DOCKER_DRIVER: overlay2
# Create the certificates inside this directory for both the server
# and client. The certificates used by the client will be created in
# /certs/client so we only need to share this directory with the
# volume mount in `config.toml`.
DOCKER_TLS_CERTDIR: "/certs"


services:
- docker:19.03.0-dind


before_script:
- apk --no-cache add docker-compose      # <---------- Mind this line
- docker info
- docker-compose --version


stage: test
script:
- docker-compose build

This worked perfectly from the first try for me. Maybe the reason other answers didn't was in some configuration of Gitlab.com shared runners, I don't know...

there is tiangolo/docker-with-compose which works:

image: tiangolo/docker-with-compose


stages:
- build
- test
- release
- clean


  

before_script:
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.gitlab.com


build:
stage: build
script:
- docker-compose -f docker-compose-ci.yml build --pull




test1:
stage: test
script:
- docker-compose -f docker-compose-ci.yml up -d
- docker-compose -f docker-compose-ci.yml exec -T php ...