Configuración del Entorno Base
Para orquestar un flujo de integración y despliegue continuo, el primer paso es preparar la infraestructura subyacente. Asegúrese de que los archivos /etc/hostname y /etc/hosts del servidor estén correctamente definidos.
Instale Docker siguiendo la documentación oficial para su distribución. Posteriormente, instale Docker Compose descargando el binario estable:
sudo curl -L "https://github.com/docker/compose/releases/download/v2.23.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
Para optimizar la descarga de imágenes, configure un mirror de registro en /etc/docker/daemon.json.
Definición de la Infraestructura con Docker Compose
La siguiente configuración levanta un proxy inverso con generación automática de certificados SSL, el servidor GitLab y su respectivo agente de ejecución (Runner). Es crucial no depender de la red bridge por defecto, ya que posteriormente el contenedor de Ansible necesitará comunicarse directamente con GitLab sin conflictos de ruteo entre múltiples redes aisladas.
version: '3.8'
services:
reverse-proxy:
image: jwilder/nginx-proxy:alpine
container_name: proxy_nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./proxy/certs:/etc/nginx/certs:ro
- ./proxy/vhost:/etc/nginx/vhost.d
- ./proxy/html:/usr/share/nginx/html
- /var/run/docker.sock:/tmp/docker.sock:ro
labels:
com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: 'true'
ssl-companion:
image: nginxproxy/acme-companion
container_name: proxy_ssl
restart: unless-stopped
volumes:
- ./proxy/certs:/etc/nginx/certs:rw
- ./proxy/vhost:/etc/nginx/vhost.d
- ./proxy/html:/usr/share/nginx/html
- /var/run/docker.sock:/var/run/docker.sock:ro
gitlab-core:
image: gitlab/gitlab-ce:latest
container_name: gitlab_core
restart: unless-stopped
hostname: 'gitlab.miempresa.local'
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://gitlab.miempresa.local'
VIRTUAL_HOST: gitlab.miempresa.local
VIRTUAL_PORT: 80
LETSENCRYPT_HOST: gitlab.miempresa.local
LETSENCRYPT_EMAIL: admin@miempresa.local
ports:
- '2222:22'
volumes:
- '/data/gitlab/config:/etc/gitlab'
- '/data/gitlab/logs:/var/log/gitlab'
- '/data/gitlab/data:/var/opt/gitlab'
ci-runner:
image: gitlab/gitlab-runner:alpine
container_name: runner_ci
restart: unless-stopped
volumes:
- '/data/runner/config:/etc/gitlab-runner'
- '/var/run/docker.sock:/var/run/docker.sock'
Registro y Ajuste del Runner
Una vez que los contenedores estén operativos, registre el agente de CI/CD utilizando el token proporcionado en el panel de administración de GitLab:
docker exec -it runner_ci gitlab-runner register \
--non-interactive \
--url "http://gitlab.miempresa.local/" \
--registration-token "TOKEN_DE_REGISTRO" \
--executor "docker" \
--docker-image "alpine:latest" \
--description "Agente de Despliegue" \
--docker-privileged \
--docker-volumes "/var/run/docker.sock:/var/run/docker.sock"
Edite el archivo de configuración generado en /data/runner/config/config.toml para evitar descargas redundantes de imágenes:
[[runners.docker]]
pull_policy = ["if-not-present"]
shm_size = 0
Gestión de Autenticación SSH
Genere un par de claves SSH en el servidor anfitrión. La clave pública debe ser agregada a la sección de claves SSH en la configuración de su cuenta de GitLab para permitir clonaciones automatizadas.
ssh-keygen -t rsa -b 4096 -C "deployer@miempresa.local"
cat ~/.ssh/id_rsa.pub
Estructura del Repositorio de Ansible
Almacene las definiciones de Ansible en un proyecto dedicado dentro de GitLab para que puedan ser inyectadas en la imagen de despliegue durante la fase de construcción.
Cree un archivo de inventario inventory/servidores_prod:
[produccion]
192.168.1.50 ansible_user=deploy
Defina el libro de jugadas principal playbooks/deploy.yml:
- hosts: produccion
vars:
app_name: "servicio_web"
target_env: "prod"
build_artifact: "/tmp/builds/package.tar.gz"
tasks:
- name: Crear directorio base de la aplicación
file:
path: "/opt/apps/{{ app_name }}-{{ target_env }}"
state: directory
mode: '0755'
- name: Limpiar código fuente anterior
file:
state: absent
path: "/opt/apps/{{ app_name }}-{{ target_env }}/src"
- name: Descomprimir nuevo artefacto
unarchive:
src: "{{ build_artifact }}"
dest: "/opt/apps/{{ app_name }}-{{ target_env }}/"
remote_src: yes
- name: Detener contenedores en ejecución
shell: docker-compose -f docker-compose.yml -f docker-compose.{{ target_env }}.yml down
args:
chdir: "/opt/apps/{{ app_name }}-{{ target_env }}"
ignore_errors: yes
- name: Desplegar nueva versión
shell: docker-compose -f docker-compose.yml -f docker-compose.{{ target_env }}.yml up -d --build
args:
chdir: "/opt/apps/{{ app_name }}-{{ target_env }}"
Configure el comportamiento de Ansible mediante ansible.cfg:
[defaults]
transport = ssh
host_key_checking = False
inventory = inventory/servidores_prod
private_key_file = ~/.ssh/id_rsa
retry_files_enabled = False
[ssh_connection]
ssh_args = -o ForwardAgent=yes -o StrictHostKeyChecking=no
Construcción de la Imagen de Despliegue
El pipeline de GitLab utilizará un contenedor personalizado con Ansible preinstalado para ejecutar las tareas en los servidores de destino.
Defina el Dockerfile:
FROM alpine:3.18
LABEL maintainer="equipo-devops"
RUN apk add --no-cache \
ansible \
git \
openssh-client \
bash
RUN mkdir -p /root/.ssh
COPY id_rsa /root/.ssh/id_rsa
RUN chmod 600 /root/.ssh/id_rsa && \
echo -e "Host *\n\tStrictHostKeyChecking no\n" > /root/.ssh/config
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
Cree el script de inicialziación entrypoint.sh:
#!/bin/bash
REPO_URL="git@gitlab.miempresa.local:infra/ansible-inventory.git"
DEST_DIR="/ansible"
if [ ! -d "$DEST_DIR" ]; then
git clone "$REPO_URL" "$DEST_DIR"
fi
cd "$DEST_DIR"
git pull origin main
exec "$@"
Asegúrese de que la clave pública del conteneder de despliegue esté registrada en el archivo ~/.ssh/authorized_keys del servidor de producción objetivo, con los permisos adecuados (chmod 600 ~/.ssh/authorized_keys).
Resolución de Problemas Comunes
Límite de tamaño de carga en GitLab:
Si el proceso de construcción falla al subir artefactos pesados, ajuste la configuración de Nginx interno de GitLab. Modifique /data/gitlab/config/gitlab.rb:
nginx['enable'] = true
nginx['client_max_body_size'] = '2048m'
Aplique los cambios reiniciando el servicio: docker exec gitlab_core gitlab-ctl reconfigure.
Aislamiento de Redes:
Si los contenedores no logran comunicarse entre sí debido a segmentaciones de red creadas por Docker Compose, genere una red externa dedicada:
docker network create infra_network
Posteriormente, asigne esta red a los servicios correspondientes en sus archivos de configuración, verificando la topología con docker network ls y brctl show para asegurar que las interfaces virtuales estén correctamente enlazadas.