Reputation: 32104
When using GitLab CI, as well as the gitlab-ci-multi-runner
, I'm unable to get internally-started Docker containers to expose their ports to the "host", which is the Docker image in which the build is running.
My .gitlab-ci.yml
file:
test:
image: docker
stage: test
services:
- docker:dind
script:
- APP_CONTAINER_ID=`docker run -d --privileged -p "9143:9143" appropriate/nc nc -l 9143`
- netstat -a
- docker exec $APP_CONTAINER_ID netstat -a
- nc -v localhost 9143
My command:
gitlab-ci-multi-runner exec docker --docker-privileged test
The output:
$ netstat -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 runner--project-1-concurrent-0:54664 docker:2375 TIME_WAIT
tcp 0 0 runner--project-1-concurrent-0:54666 docker:2375 TIME_WAIT
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node Path
$ docker exec $APP_CONTAINER_ID netstat -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:9143 0.0.0.0:* LISTEN
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node Path
$ nc -v localhost 9143
ERROR: Build failed: exit code 1
FATAL: exit code 1
What am I doing wrong here?
Original Question Follows - above is a shorter, easier-to-test example
I have an application image that listens on port 9143
. Its startup and config is managed via docker-compose.yml
, and works great on my local machine with docker-compose up
- I can access localhost:9143
without issue.
However, when running on GitLab CI (the gitlab.com
version) via a shared runner, the port doesn't seem to be exposed.
The relevant portion of my .gitlab-ci.yml
:
test:
image: craigotis/buildtools:v1
stage: test
script:
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.gitlab.com/craigotis/myapp
- docker-compose up -d
- sleep 60 # a temporary hack to get the logs
- docker-compose logs
- docker-machine env
- docker-compose port app 9143
- netstat -a
- docker-compose ps
- /usr/local/bin/wait-for-it.sh -h localhost -p 9143 -t 60
- cd mocha
- npm i
- npm test
- docker-compose down
The output is:
$ docker-compose logs
...
app_1 | [Thread-1] INFO spark.webserver.SparkServer - == Spark has ignited ...
app_1 | [Thread-1] INFO spark.webserver.SparkServer - >> Listening on 0.0.0.0:9143
app_1 | [Thread-1] INFO org.eclipse.jetty.server.Server - jetty-9.0.z-SNAPSHOT
app_1 | [Thread-1] INFO org.eclipse.jetty.server.ServerConnector - Started ServerConnector@6919dc5{HTTP/1.1}{0.0.0.0:9143}
...
$ docker-compose port app 9143
0.0.0.0:9143
$ netstat -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 runner-e11ae361-project-1925166-concurrent-0:53646 docker:2375 TIME_WAIT
tcp 0 0 runner-e11ae361-project-1925166-concurrent-0:53644 docker:2375 TIME_WAIT
tcp 0 0 runner-e11ae361-project-1925166-concurrent-0:53642 docker:2375 TIME_WAIT
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node Path
$ docker-compose ps
stty: standard input: Not a tty
Name Command State Ports
----------------------------------------------------------------------------------------
my_app_1 wait-for-it.sh mysql_serve ... Up 8080/tcp, 0.0.0.0:9143->9143/tcp
mysql_server docker-entrypoint.sh --cha ... Up 3306/tcp
$ /usr/local/bin/wait-for-it.sh -h localhost -p 9143 -t 60
wait-for-it.sh: waiting 60 seconds for localhost:9143
wait-for-it.sh: timeout occurred after waiting 60 seconds for localhost:9143
The contents of my docker-compose.yml
:
version: '2'
networks:
app_net:
driver: bridge
services:
app:
image: registry.gitlab.com/craigotis/myapp:latest
depends_on:
- "db"
networks:
- app_net
command: wait-for-it.sh mysql_server:3306 -t 60 -- java -jar /opt/app*.jar
ports:
- "9143:9143"
db:
image: mysql:latest
networks:
- app_net
container_name: mysql_server
environment:
- MYSQL_ALLOW_EMPTY_PASSWORD=true
It seems like my application container is listening on 9143
, and it's properly exposed to the shared GitLab runner, but it doesn't seem to actually be exposed. It works fine on my local machine - is there some special workaround/tweak I need to make this work inside a Docker container running on GitLab?
Upvotes: 29
Views: 20931
Reputation: 1985
In case you GitLab CI Runner run with Docker-executor via socket binding use host.docker.internal
-host, because your app is running on the host machine but not on the guest.
# Run and ssh into dind-container
docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock docker:20.10-dind /bin/sh
# Next commands run in dind-container
docker run --rm -d -p 8888:80 nginx:alpine
...
wget -qO- "http://localhost:8888/"
wget: can't connect to remote host (127.0.0.1): Connection refused
wget -qO- "http://127.0.0.1:8888/"
wget: can't connect to remote host (127.0.0.1): Connection refused
wget -qO- "http://docker:8888/"
wget: bad address 'docker:8888'
wget -qO- "http://host.docker.internal:8888/"
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...
Upvotes: 2
Reputation: 1053
When using docker:dind
a container is created and your docker-compose containers get setup within it. It exposes the ports to localhost within the docker:dind
container. You cannot access this as localhost
from the environment that your code is executing in.
A hostname of docker
is setup for you to reference this docker:dind
container. You can check by using cat /etc/hosts
.
Instead of referencing localhost:9143
you should use docker:9143
.
Upvotes: 21
Reputation: 2741
Your docker-compose.yml
seems to be ok.
But I think there is error with your ip or port routing. As I can see from your shared info your app is running on port 9143 on ip 0.0.0.0 as 0.0.0.0:9143.
and you are accessing it as localhost:9143
,
which can be interpreted as 127.0.0.1:9143
.
According to this.
127.0.0.1 is the loopback address (also known as localhost).
0.0.0.0 is a non-routable meta-address used to designate an invalid, unknown, or non-applicable target (a ‘no particular address’ place holder).
Can you try to run your app on 127.0.0.1:9143
then share the result.
UPDATE
or you can use service to run it by service name as documentation suggest:
The services keyword defines just another docker image that is run during your build and is linked to the docker image that the image keyword defines. This allows you to access the service image during build time.
The service container for MySQL will be accessible under the hostname mysql
.
So, in order to access your database service you have to connect to the host named mysql instead of a socket or localhost
.
Upvotes: 1
Reputation: 2672
Usually a docker machine won't run on localhost, but on a docker host with some other ip address. Try using docker-machine ip
to get your docker host ip.
Upvotes: 0
Reputation: 1329782
The offical gitab-ci on gitlab.com documentation refers to the example of PostgreSQL
Its working CI does not try to connect to localhost, but rather to the service name
The
services
keyword defines just another docker image that is run during your build and is linked to the docker image that the image keyword defines. This allows you to access the service image during build time.The service container for MySQL will be accessible under the hostname
mysql
.
So, in order to access your database service you have to connect to the host namedmysql
instead of a socket orlocalhost
.
You could check if this applies in your case, and try accessing your application service in app:9143
instead of localhost:9143
.
Upvotes: 13