Publish a Docker image to Docker Hub using GitLab
Tags: git, docker
Published: 2020-06-26 21:14:06

If you need to create a custom Docker image that includes the tools you need for your projects, a way to automate the building process and publish that image on Docker Hub is using GitLab CI.

First you create a new GitLab project and add a Dockerfile with instructions on how to build the image. The following is the Dockerfile for an image that contains development tools for Python and Rust, based on the official Docker image of Rust, that you can find [here](https://hub.docker.com/_/rust).

```docker
FROM rust:slim-buster
RUN apt-get -y update
RUN apt-get install -y sudo

RUN adduser --disabled-password --gecos '' admin
RUN adduser admin sudo
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
RUN chown -R admin /home/admin

USER admin

RUN sudo apt-get install -y python3 make build-essential libssl-dev zlib1g-dev libbz2-dev \
    libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \
    xz-utils tk-dev libffi-dev liblzma-dev python-openssl git && \
    curl https://pyenv.run | bash && \
    curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python3

ENV HOME /home/admin
ENV PYENV_ROOT $HOME/.pyenv
ENV POETRY_ROOT $HOME/.poetry
ENV CARGO_ROOT /usr/local/cargo
ENV PATH $PYENV_ROOT/shims:$PYENV_ROOT/bin:$PATH
ENV PATH $POETRY_ROOT/bin:$PATH
ENV PATH $CARGO_ROOT/bin:$PATH
```

Then go to `Settings` => `CI/CD`, click on `Expand` in the `Variables` section and add the following variables:
- `CI_REGISTRY`
- `CI_REGISTRY_IMAGE`
- `CI_REGISTRY_PASSWORD`
- `CI_REGISTRY_USER`

`CI_REGISTRY_USER` must contain your Docker HUB username.
`CI_REGISTRY_PASSWORD` must contain your Docker HUB password or your access token (if you have 2FA activated).
`CI_REGISTRY` must contain `docker.io`.
`CI_REGISTRY_IMAGE` must contain `index.docker.io/username/image_name`.

Now you have to configure GitLab CI, add a `.gitlab-ci.yml` file. The content of this file is (it can be created using a template from the editor):

```yaml
# This file is a template, and might need editing before it works on your project.
docker-build-master:
  # Official docker image.
  image: docker:latest
  stage: build
  services:
    - docker:dind
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
  script:
    - docker build --pull -t "$CI_REGISTRY_IMAGE" .
    - docker push "$CI_REGISTRY_IMAGE"
  only:
    - master

docker-build:
  # Official docker image.
  image: docker:latest
  stage: build
  services:
    - docker:dind
  before_script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
  script:
    - docker build --pull -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG" .
    - docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG"
  except:
    - master
```

Once you add this file, the pipeline will run.

![Pipeline running](https://dev-to-uploads.s3.amazonaws.com/i/5j4r192y9x92nhdorlrl.png)

And your image will be available from Docker Hub for you to use it on your projects.
![Docker Hub](https://dev-to-uploads.s3.amazonaws.com/i/em0movktv8sgplhy9je2.png)

And finally, if you want the building process to be executed daily, weekly or any time as you need, you can schedule the pipeline on your repository.

Go to `CI/CD` => `Schedules`, add a `New schedule` and configure according to your need.
![Schedule a new pipeline](https://dev-to-uploads.s3.amazonaws.com/i/18w6ze4yjq42n4mmomse.png)