## Рекап успешной конфигурации --- ### 1. GitLab в Docker **Запуск контейнера** (уже был настроен, ключевое — порты): ```bash docker run -d \ --hostname gitlab.local \ --publish 85:80 \ --publish 443:443 \ --publish 2223:22 \ --name gitlab \ --restart always \ -v /srv/gitlab/config:/etc/gitlab \ -v /srv/gitlab/logs:/var/log/gitlab \ -v /srv/gitlab/data:/var/opt/gitlab \ gitlab/gitlab-ce:latest ``` **Критическая настройка внутри контейнера** (чтобы nginx слушал на всех интерфейсах): ```bash docker exec -it gitlab bash cat > /etc/gitlab/gitlab.rb << 'EOF' external_url 'http://10.0.2.15:85' nginx['listen_addresses'] = ['0.0.0.0'] nginx['listen_port'] = 80 EOF gitlab-ctl reconfigure exit docker restart gitlab ``` --- ### 2. GitLab Runner **Установка:** ```bash sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64 sudo chmod +x /usr/local/bin/gitlab-runner sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner sudo gitlab-runner start ``` **Регистрация** (`http://172.17.0.1:85` — IP docker bridge, доступный изнутри контейнеров): ```bash sudo gitlab-runner register # URL: http://172.17.0.1:85 # Token: [из GitLab → Settings → CI/CD → Runners] # Executor: docker # Default image: docker:latest ``` **Конфиг `/etc/gitlab-runner/config.toml`** (главное — `url` и `clone_url` на IP docker bridge): ```toml [[runners]] name = "gitlab-runner" url = "http://172.17.0.1:85" token = "..." executor = "docker" clone_url = "http://172.17.0.1:85" [runners.docker] image = "docker:latest" privileged = true ``` **Разрешить untagged jobs** в GitLab → Settings → CI/CD → Runners → Edit → ☑️ Run untagged jobs. --- ### 3. Структура проекта ``` myapp/ ├── main.go ├── go.mod ├── Dockerfile └── .gitlab-ci.yml ``` **`main.go`** — минимальный HTTP-сервер: ```go package main import ( "fmt" "net/http" "os" "time" ) func main() { port := os.Getenv("PORT") if port == "" { port = "8080" } http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello from CI/CD!\nVersion: 1.0.0\nTime: %s\n", time.Now().Format(time.RFC3339)) }) http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") fmt.Fprintln(w, `{"status":"ok"}`) }) fmt.Printf("Server starting on :%s\n", port) http.ListenAndServe(":"+port, nil) } ``` **`go.mod`**: ```text module myapp go 1.23 ``` **`Dockerfile`** — копирует уже собранный бинарник (не собирает заново): ```dockerfile FROM alpine:latest COPY server /server RUN chmod +x /server ENV PORT=8080 EXPOSE 8080 ENTRYPOINT ["/server"] ``` --- ### 4. CI/CD Pipeline (`.gitlab-ci.yml`) ```yaml stages: - build - deploy build: stage: build image: golang:1.23-alpine script: - CGO_ENABLED=0 go build -ldflags="-s -w" -o server main.go artifacts: paths: - server deploy: stage: deploy image: alpine:latest dependencies: - build before_script: - apk add --no-cache openssh-client - mkdir -p ~/.ssh && chmod 700 ~/.ssh - echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa && chmod 600 ~/.ssh/id_rsa - ssh-keyscan -H $DEPLOY_HOST >> ~/.ssh/known_hosts script: - | ssh $DEPLOY_USER@$DEPLOY_HOST "mkdir -p ~/myapp" scp server Dockerfile $DEPLOY_USER@$DEPLOY_HOST:~/myapp/ ssh $DEPLOY_USER@$DEPLOY_HOST << EOF set -e cd ~/myapp docker stop myapp || true docker rm myapp || true docker build -t myapp:latest . docker run -d --name myapp --restart unless-stopped -p 8080:8080 myapp:latest docker image prune -f docker ps | grep myapp EOF only: - master ``` --- ### 5. Целевой сервер (деплой) **SSH-ключи** (генерируем на сервере с GitLab): ```bash ssh-keygen -t ed25519 -C "gitlab-deploy" -f ~/.ssh/gitlab_deploy ``` **На целевом сервере:** ```bash sudo useradd -m -s /bin/bash deploy sudo usermod -aG docker deploy sudo mkdir -p /home/deploy/.ssh sudo nano /home/deploy/.ssh/authorized_keys # Вставить содержимое ~/.ssh/gitlab_deploy.pub sudo chmod 700 /home/deploy/.ssh sudo chmod 600 /home/deploy/.ssh/authorized_keys sudo chown -R deploy:deploy /home/deploy/.ssh sudo reboot ``` --- ### 6. GitLab Variables **Project → Settings → CI/CD → Variables:** | Variable | Значение | |----------|----------| | `SSH_PRIVATE_KEY` | Содержимое `~/.ssh/gitlab_deploy` (приватный ключ) | | `DEPLOY_HOST` | IP целевого сервера | | `DEPLOY_USER` | `deploy` | --- ### 7. Проверка деплоя ```bash ssh deploy@ docker ps curl http://localhost:8080 curl http://localhost:8080/health ``` --- ### Итоговые цифры | Параметр | Значение | |----------|----------| | Размер Docker-образа приложения | ~10 МБ | | Внешних зависимостей | 0 | | Этапов CI/CD | 2 (build → deploy) | | Размер runner-образа | не критичен (используется стандартный alpine) | **Push в `master` → build → scp на сервер → docker build → docker run → приложение доступно на порту 8080.**