CI for frontend: Gitlab, Traefik, Docker

Every self-respecting project should involve QA engineers. Every day they will be faced with the task of verifying the execution of tasks in separate branches. Very often, the process of switching to the desired branch, assembly and testing takes a lot of time, moreover, it is not always possible locally to completely recreate the most identical combat environment.

The purpose of this article is to show a simple technique of setting up a stand for several branches. This article is written by developers from the developer, so it is unlikely to be of significant interest to professional DevOps engineers.

Requirements:

  • Gitlab (bare metal / cloud)
  • Dedicated server
  • Free domain

Step One: Configure Gitlab


  1. Install Gitlab Runner on your dedicated server
  2. Create a docker that supports docker builds of images
  3. Turn on Container Registry

Step Two: Server Setup


  1. Install Docker
  2. Install Compose
  3. Create a user:

    # создаем пользователя для деплоя образов, разрешаем ему работу с докером
    $ sudo adduser deployer
    $ sudo groupadd docker
    $ sudo usermod -aG docker deployer
    # генерим ssh ключи
    $ su deployer
    $ ssh-keygen -t rsa
    (when asked for a passphrase, enter no passphrase)
    # разрешаем подключение к серверу с только что созданным ключом 
    $ cp ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys
    

  4. Configure traefik (server proxying requests to Docker containers based on their labels (labels)):

    $ sudo mkdir -p /opt/traefik
    $ docker network create web
    # файлы настроек docker-compose & traefik упрощены до предела и должны быть достаточно понятными

    /opt/traefik/docker-compose.yml

    version: '2'
    services:
      traefik:
        image: traefik:1.4.6
        restart: always
        ports:
          - 80:80
        networks:
          - web
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock
          - ./traefik.toml:/traefik.toml
        container_name: traefik
    networks:
      web:
        external: true

    /opt/traefik/traefik.toml

    Replace DOMAIN.COM with your domain.

    debug = true
    checkNewVersion = true
    logLevel = "ERROR"
    defaultEntryPoints = ["http"]
    [entryPoints]
      [entryPoints.http]
      address = ":80"
    [retry]
    [docker]
    endpoint = "unix:///var/run/docker.sock"
    domain = "DOMAIN.COM"
    watch = true
    exposedbydefault = false

  5. Run traefik:

    cd /opt/traefik && docker-compose up -d

  6. Add an entry for DOMAIN.COM of the form '*' - IP of the dedicated server.

Step three: prepare the repository


  1. Add the Dockerfile to the root of the repository:

    FROM node:8.9as build-deps
    WORKDIR /usr/src/app
    COPY package.json ./
    RUN npm i
    COPY . ./
    RUN npm run build
    FROM nginx:1.12-alpine
    COPY--from=build-deps /usr/src/app/dist /usr/share/nginx/html
    EXPOSE 80
    CMD ["nginx", "-g", "daemon off;"]
    

    Change

    npm run build

    on your build team. Similarly edit the path

    /usr/src/app/dist

    changing dist to your build directory.
    You can read more about the structure and commands of Docherfaye here .
  2. Add the .gitlab-ci.yml file with the image assembly section:

    image: docker:stable
    variables:
      DOCKER_HOST: tcp://docker:2375/
      DOCKER_DRIVER: overlay2
      GITLAB_DOMAIN: gitlab.com
    services:
      - docker:dind
    stages:
      - build
    build_staging:
      stage: build
      script:
        - export GITLAB_DOMAIN=gitlab.com
        - export CONTAINER_IMAGE=$GITLAB_DOMAIN/frontend/main/image
        - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN$GITLAB_DOMAIN
        - docker pull $CONTAINER_IMAGE:$CI_COMMIT_REF_SLUG || true
        - export URL="Host:${CI_COMMIT_REF_NAME}.tests.DOMAIN.COM"
        - docker build -t $CONTAINER_IMAGE:$CI_COMMIT_REF_SLUG . --label "traefik.backend=${CI_COMMIT_REF_NAME}" --label "traefik.frontend.rule=${URL}"
        - docker push $CONTAINER_IMAGE:$CI_COMMIT_REF_SLUG
  3. Add the private key deployer@DOMAIN.COM to the repository settings (Settings -> CI / CD -> Variables) as SSH_PRIVATE_KEY
  4. Add deploy sections:

    stages:
      - build
      - deploy
    /// ....
    deploy_staging:
      stage: deploy
      image: kroniak/ssh-client:3.6
      script:
        - mkdir ~/.ssh
        - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
        - eval $(ssh-agent -s)
        - ssh-add <(echo "$SSH_PRIVATE_KEY")
        - ssh deployer@DOMAIN.COM "docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN$GITLAB_DOMAIN"
        - ssh deployer@DOMAIN.COM "docker stop frontend_${CI_COMMIT_REF_SLUG}" || true
        - ssh deployer@DOMAIN.COM "docker rm frontend_${CI_COMMIT_REF_SLUG}" || true
        - ssh deployer@DOMAIN.COM "docker rmi GITLAB-DOMAIN.COM/frontend/main/image:${CI_COMMIT_REF_SLUG}" || true
        - ssh deployer@DOMAIN.COM "docker run --name frontend_${CI_COMMIT_REF_SLUG} --network=web -d $GITLAB_DOMAIN/frontend/main/image:${CI_COMMIT_REF_SLUG}"
      environment:
        name: review/$CI_COMMIT_REF_NAME
        url: http://${CI_COMMIT_REF_NAME}.tests.DOMAIN.COM
        on_stop: stop_staging
    stop_staging:
      stage: deploy
      image: kroniak/ssh-client:3.6
      variables:
        GIT_STRATEGY: none
      script:
        - mkdir ~/.ssh
        - '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
        - eval $(ssh-agent -s)
        - ssh-add <(echo "$SSH_PRIVATE_KEY")
        - ssh deployer@DOMAIN.COM "docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN GITLAB-DOMAIN.COM"
        - ssh deployer@DOMAIN.COM "docker stop frontend_${CI_COMMIT_REF_SLUG}" || true
        - ssh deployer@DOMAIN.COM "docker rm frontend_${CI_COMMIT_REF_SLUG}" || true
        - ssh deployer@DOMAIN.COM "docker rmi $GITLAB_DOMAIN/frontend/main/image:${CI_COMMIT_REF_SLUG}" || truewhen: manual
      environment:
        name: review/$CI_COMMIT_REF_NAME
        action: stop

The above steps are enough to get the following result:

  • Each new commit into a branch initiates the assembly and development of the latest actual code at% branch_name% .tests.DOMAIN.COM
  • Gitlab includes an environment mechanism that allows you to create / delete / open closed images in a couple of touches.

Next steps:

  • Set up a separate section for the wizard builds. In the case of the master, it is reasonable to tag the image via COMMIT_SHA
  • Add configs to nginx in docker
  • To forward the build parameters of the bundle through the ARG and ENV mechanisms of the dockfile
  • Configure use of cache from image for assemblies

Based on the article.

Also popular now: