Gabriel Cachadiña

Integración de Gitea con Docker Registry

· Gabriel Cachadiña

Muchas empresas dependen de terceros para el versionado de su código, para hacer pruebas sobre el mismo y para crear contenedores docker. Para reducir esta dependencia, he decidido mostrar cómo mantengo mis proyectos en mis propios entornos, obteniendo mayor autonomía, estabilidad y seguridad en mi forma de trabajar.

Programas

Gitea

Gitea es una excelente alternativa a Github, pudiendo mantener tantos repositorios como se quiera y teniendo prácticamente todas las funcionalidades de Github. Con esto tendremos una solución para mantener nuestro código y versionado del mismo en nuestra infraestructura.

Gitea Act Runner

Gitea Act Runner es un servicio que permite correr Gitea actions, para tener pipelines parecidos a los que se tienen en Github. Este servicio puede correrse en otro servidor, para separar el servidor CI/CD del servidor que tiene el versionado del código. A continuación muestro un docker compose que permite correr Gitea junto a Gitea Act Runner

 1services:
 2  server:
 3    image: docker.io/gitea/gitea:latest
 4    container_name: gitea
 5    environment:
 6      - USER_UID=1000
 7      - USER_GID=1000
 8      - ROOT_URL=https://gitea.gabrielcachadina.com/
 9      - GITEA__SERVICE__REGISTER_MANUAL_CONFIRM=true
10    restart: always
11    networks:
12      - gitea
13    volumes:
14      - ./Gitea:/data
15      - /etc/timezone:/etc/timezone:ro
16      - /etc/localtime:/etc/localtime:ro
17    ports:
18      - "3000:3000"
19      - "222:22"
20
21  runner:
22    image: docker.io/gitea/act_runner:nightly
23    environment:
24      GITEA_INSTANCE_URL: "https://gitea.gabrielcachadina.com"
25      GITEA_RUNNER_REGISTRATION_TOKEN: "{{ gitea_runner }}"
26      GITEA_RUNNER_NAME: "Gitea Runner Localhost"
27    volumes:
28      - ./GiteaRunner/data:/data
29      - /var/run/docker.sock:/var/run/docker.sock
30    networks:
31      - gitea
32    restart: always
33
34networks:
35  gitea:
36    external: false

Se deberá sustituir el token de Gitea y deberá añadirse el runner dentro del panel de administrador de Gitea. Gitea Runner Config

Docker Registry

Docker Registry permite almacenar contenedores Docker de los servicios que creemos, en mi caso yo almaceno los contenedores en el mismo servidor que corre Gitea, aunque este servicio podría desplegarse en un servidor independiente. Para correr este servicio se podría usar el siguiente docker-compose:

 1---
 2services:
 3  registry:
 4    image: registry:latest
 5    ports:
 6      - "5000:5000"
 7    environment:
 8      REGISTRY_AUTH: htpasswd
 9      REGISTRY_AUTH_HTPASSWD_REALM: Registry
10      REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password
11      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /registry-data
12    volumes:
13      - ./DockerRegistry/auth:/auth
14      - ./DockerRegistry/registry-data:/registry-data
15    restart:
16      always

Para generar la contraseña se deberá generar el archivo registry.password, de la siguiente forma:

1htpasswd -B -c /auth/registry.password "$DOCKERREGISTRY_USER" "$DOCKERREGISTRY_PASS"

Aplicación Real

De forma de ejemplo aquí muestro un código de un microservicio que uso actualmente para retornar todos los datos geográficos de una pareja de coordenadas mediante una API. Este código pequeño solo contiene un añadido inusual, la carpeta .gitea/workflows. Gitea Repository Dentro de la carpeta tengo un workflow que, al actualizar el código, inicia una máquina Ubuntu, crea el contenedor de docker y lo sube a Docker Registry:

 1name: Build and Push Docker Image (Go)
 2
 3on:
 4  push:
 5    branches:
 6      - main
 7
 8jobs:
 9  build-and-push:
10    runs-on: ubuntu-latest
11
12    steps:
13      - name: Manual Git clone from Gitea
14        run: |
15          git clone https://USERNAME:${{ secrets.GITEA_TOKEN }}@gitea.gabrielcachadina.com/GabrielCachadina/ms_gps_location_data.git
16          cd ms_gps_location_data
17          git checkout main
18
19      - name: Log in to Docker Registry
20        working-directory: ./ms_gps_location_data
21        run: |
22          echo "${{ secrets.DOCKER_PASSWORD }}" | docker login dockerregistry.gabrielcachadina.com -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
23
24      - name: Clean up Docker images
25        working-directory: ./ms_gps_location_data
26        run: |
27          docker image prune -f
28          docker image rm dockerregistry.gabrielcachadina.com/ms_gps_location_data:latest || true
29
30      - name: Build Docker image
31        working-directory: ./ms_gps_location_data
32        run: |
33          docker build --no-cache -t dockerregistry.gabrielcachadina.com/ms_gps_location_data:latest .
34
35      - name: Push Docker image
36        working-directory: ./ms_gps_location_data
37        run: docker push dockerregistry.gabrielcachadina.com/ms_gps_location_data:latest

Finalmente, para correr este servicio en otros servidores, se podría hacer de forma manual, pero yo prefiero levantar los micro servicios mediante ansible, en concreto creo un rol para cada servicio, quedando este rol como:

1.
2├── defaults
3│   └── main.yml
4├── meta
5│   └── main.yml
6└── tasks
7    └── main.yml

y el archivo tasks/main.yml:

  1---
  2################# Directory Config #################
  3- name: Ensure application directory exists
  4  file:
  5    path: "{{ app_dest }}"
  6    state: directory
  7    owner: '1000'
  8    group: '1000'
  9    mode: '0755'
 10
 11- name: Ensure logs directory exists
 12  file:
 13    path: "{{ app_dest }}/logs"
 14    state: directory
 15    owner: '1000'
 16    group: '1000'
 17    mode: '0755'
 18################# Save the image localy #################
 19- name: Login to private Docker registry on controller
 20  delegate_to: localhost
 21  run_once: true
 22  community.docker.docker_login:
 23    registry_url: "dockerregistry.gabrielcachadina.com"
 24    username: "{{ dockerregistry_user }}"
 25    password: "{{ dockerregistry_pass }}"
 26  become: false
 27
 28- name: Pull Docker image on controller (ensure it's present)
 29  delegate_to: localhost
 30  run_once: true
 31  community.docker.docker_image:
 32    name: "{{ image_name }}"
 33    source: pull
 34    force_source: true
 35  become: false
 36
 37- name: Save Docker image on controller to temporary file
 38  delegate_to: localhost
 39  run_once: true
 40  command: >
 41    docker save {{ image_name }} -o /tmp/{{ container_name }}.tar
 42  become: false
 43
 44- name: Save Docker image on controller to temporary file
 45  delegate_to: localhost
 46  run_once: true
 47  command: >
 48    docker save {{ image_name }} -o /tmp/{{ container_name }}.tar
 49  become: false
 50
 51- name: Change the permissions for the tarball
 52  delegate_to: localhost
 53  run_once: true
 54  file:
 55    path: "/tmp/{{ container_name }}.tar"
 56    mode: "0644"
 57  become: false
 58
 59################# Push and Compile #################
 60
 61- name: Remove old container
 62  community.docker.docker_container:
 63    name: "{{ container_name }}"
 64    state: absent
 65    force_kill: true
 66
 67- name: Remove existing image from remote
 68  community.docker.docker_image:
 69    name: "{{ image_name }}"
 70    state: absent
 71
 72- name: Copy Docker image tarball to remote host
 73  copy:
 74    src: "/tmp/{{ container_name }}.tar"
 75    dest: "/tmp/{{ container_name }}.tar"
 76    mode: '0644'
 77
 78- name: Load Docker image from tarball
 79  community.docker.docker_image:
 80    name: "{{ image_name }}"
 81    load_path: "/tmp/{{ container_name }}.tar"
 82    source: load
 83    force_source: true
 84
 85- name: Remove temporary tar file from remote
 86  file:
 87    path: "/tmp/{{ container_name }}.tar"
 88    state: absent
 89
 90
 91- name: Start the container
 92  community.docker.docker_container:
 93    name: "{{ container_name }}"
 94    image: "{{ image_name }}"
 95    state: started
 96    restart_policy: "{{ restart_policy }}"
 97    privileged: yes
 98    network_mode: host
 99    env:
100      TZ: Europe/Madrid
101    volumes:
102      - "{{ app_dest }}/logs:/app/logs"
103    ports:
104      - "22003:22003"
105
106################# Clean from Localhost #################
107
108- name: Remove temporary tar file from controller (cleanup)
109  delegate_to: localhost
110  run_once: true
111  file:
112    path: "/tmp/{{ container_name }}.tar"
113    state: absent
114  become: false
115
116- name: Remove Docker image from controller (cleanup)
117  delegate_to: localhost
118  run_once: true
119  community.docker.docker_image:
120    name: "{{ image_name }}"
121    state: absent
122    force_absent: true
123  become: false

Como nota final, remarcar que estos servicios mostrados están todos tras un reverse proxy usando NGINX, para conseguir seguir HTTPS en los mismos y así evitar problemas de seguridad. Además de esto los puertos que usan los servicios están deshabilitados dentro del firewall de los servicios.

#gnu/linux #self-hosted

Reply to this post by email ↪