Всё началось с того, что в 2024 году мне в руки попал интересный экземпляр — мини-ПК ( Характеристики: Процессор Intel N100 / RAM 16 GB / SSD 500 GB.) решив, что раз уж основная рабочая лошадка у меня уже есть, этот мики-ПК предстоит переделать в мини-сервер и приспособить к мои pet-проектам. Заказал себе 1Гбит интернет, белый IP адрес и ушел творить.
Первая моя задумка с треком провалилась, т.к изначально я разместил на нем Gitlab Server, NextCloud и пару своих приложений. «Жужжал» он не по-детски, я взаправду подумал, что в какой-то момент он просто отлетит к своим небесным производителям. Кто же знал, что Gitlab настолько прожорливый. Удалив все приложения и полностью переустановив Ubuntu, я пришел к своей второй попытке.
Вторая задумка в принципе тоже не оказалась жизнеспособной, т.к ни о каком k8s я в тот момент не думал и просто пихал все свои приложения на голое железо. Совсем скоро я понял, что именно решает docker и k8s и что со всеми моими зависимостями ПО нужно что-то решать. Решать нужно решительно и серьезно. Поэтому заморозил сервер до лучших времен, отключив ему питание и ушел учиться на DevOps.
Спустя полгода обучения я вернулся к своему серверу и уже знал примерно что я хочу сделать:
Никаких тяжелых приложений на сервере, только свои развернутые проекты.
Все тяжелые операции отдаются стационарному старшему брату. Его я собирал для игр, поэтому развернуть на нём тот же Gitlab не составит проблем.
Определив основные положения пора воплощать свои задумки в жизнь. Для начала создадим папку docker в которой будем складывать данные со своих контейнеров.
Настройка роутера
У меня не сильно мощный роутер, к тому же достаточно загруженный, но для моих нужд пока хватает. На роутере нужно настроить статичный IP для личного ПК и «кластера». Закрыть все порты кроме 80 и 443 в целях безопасности,а 80 и 443 перенаправить на свой сервер.
Nginx-proxy
Первое что я делаю - устанавливаю nginx-proxy, чтобы проксировать все свои запущенные контейнеры и использовать единый 80 и 443 порты.
./docker/nginx-proxy/docker-compose.yml
services:
nginx-proxy:
image: nginxproxy/nginx-proxy
restart: always
ports:
- 80:80
- 443:443
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- "./my_custom_proxy_settings.conf:/etc/nginx/conf.d/my_custom_proxy_settings.conf"
К нему настройку для загрузки больших файлов ./my_custom_proxy_settings.conf состоящий из 1 строки
client_max_body_size 1G;
Gitlab Server
Запускаю gitlab и runners к нему. Необходимо выпустить свой ssl сертификат для gitlab registry, без него даже из локальной сети не получится получить свой собранный образ.
./docker/gitlab/docker-compose.yml
name: "gitlab-local"
networks:
gitlab-network:
driver: bridge
nginx-proxy_default:
external: true
services:
gitlab:
image: gitlab/gitlab-ee:latest
container_name: gitlab
restart: always
hostname: 'gitlab.local'
environment:
VIRTUAL_HOST: "gitlab.local"
VIRTUAL_PORT: 80
GITLAB_OMNIBUS_CONFIG: |
# Add any other gitlab.rb configuration here, each on its own line
external_url 'http://gitlab.local'
registry['enable'] = true
registry_external_url 'https://gitlab.local:5050'
registry_nginx['ssl_certificate'] = "/etc/gitlab/gitlab.local.crt"
registry_nginx['ssl_certificate_key'] = "/etc/gitlab/gitlab.local.key"
ports:
- '5050:5050'
volumes:
- './gitlab-data/config:/etc/gitlab'
- './gitlab-data/logs:/var/log/gitlab'
- './gitlab-data/data:/var/opt/gitlab'
- './gitlab-data/certificate.crt:/etc/gitlab/gitlab.local.crt'
- './gitlab-data/privateKey.key:/etc/gitlab/gitlab.local.key'
shm_size: '256m'
networks:
- gitlab-network
- nginx-proxy_default
# RUNNER
gitlab-runner:
image: gitlab/gitlab-runner
container_name: gitlab-runner
restart: always
depends_on:
- gitlab
volumes:
- ./gitlab-runners/config:/etc/gitlab-runner
- /var/run/docker.sock:/var/run/docker.sock
networks:
- gitlab-network
- nginx-proxy_default
Здесь и далее везде где мне требуется 80/443 порты, я подключаю к образам сеть nginx-proxy_default.
Для runner я использую такой config:
./docker/gitlab/gitlab-runners/config
concurrent = 20 # A global setting for job concurrency that applies to all runner sections defined in this `config.toml` file
log_level = "warning"
check_interval = 3 # Value in seconds
[[runners]]
name = "Runner1"
url = "http://gitlab"
executor = "docker"
token = "<SECRET_TOKEN>"
[runners.docker]
tls_verify = false
image = "gitlab/gitlab-runner:latest"
priviledged = true
disable_cache = false
volumes = ["/cache"]
pull_policy = "if-not-present"
cache_dir = "/cache/gitlab"
network_mode = "host"
SECRET_TOKEN
- получается в gitlab при создании ранера.
Дополнительно можно поднять SonarQube образ для статического анализа кода.
./docker/sonar/docker-compose.yml
services:
sonarqube:
image: sonarqube:community
restart: always
hostname: sonarqube
container_name: sonarqube
read_only: true
depends_on:
db:
condition: service_healthy
environment:
SONAR_JDBC_URL: jdbc:postgresql://db:5432/sonar
SONAR_JDBC_USERNAME: sonar
SONAR_JDBC_PASSWORD: sonar
VIRTUAL_HOST: "sonarqube.local"
VIRTUAL_PORT: 9000
volumes:
- sonarqube_data:/opt/sonarqube/data
- sonarqube_extensions:/opt/sonarqube/extensions
- sonarqube_logs:/opt/sonarqube/logs
- sonarqube_temp:/opt/sonarqube/temp
networks:
- sonarqube-network
- nginx-proxy_default
db:
image: postgres:17
restart: always
healthcheck:
test: ["CMD-SHELL", "pg_isready"]
interval: 10s
timeout: 5s
retries: 5
hostname: postgresql
container_name: postgresql
environment:
POSTGRES_USER: sonar
PGUSER: sonar
POSTGRES_PASSWORD: sonar
POSTGRES_DB: sonar
volumes:
- postgresql:/var/lib/postgresql
- postgresql_data:/var/lib/postgresql/data
networks:
- sonarqube-network
- nginx-proxy_default
networks:
sonarqube-network:
driver: bridge
nginx-proxy_default:
external: true
volumes:
sonarqube_data:
driver: "local"
driver_opts:
o: bind
device: "./data/sonarqube-data"
type: none
sonarqube_temp:
driver: local
driver_opts:
o: bind
device: "./data/sonarqube-temp"
type: none
sonarqube_extensions:
driver: local
driver_opts:
o: bind
type: none
device: "./data/sonarqube-extensions"
sonarqube_logs:
driver: local
driver_opts:
o: bind
type: none
device: "./data/sonarqube-logs"
postgresql:
driver: local
driver_opts:
o: bind
type: none
device: "./data/postgresql"
postgresql_data:
driver: "local"
driver_opts:
o: bind
device: "./data/postgres-data"
type: none
На этом основная настройка стационарного ПК завершена. Можно приступить к настройке сервера.
Настройка «Кластера»
Я выбрал использование k3s для сервера. Т.к это самый простой способ быстро настроить kubernetes с возможность расширения до нескольких нод. Команда установки выглядит следующим образом
sudo k3s server &
# Kubeconfig is written to /etc/rancher/k3s/k3s.yaml
sudo k3s kubectl get node
Теперь для того чтобы использовать сервер в гитлабе нужно скопировать ~/.kube/config в файл и поменять IP адрес на локальный IP сервера.
Чтобы пулить образы из гитлаба, нужно добавить gitlab.local в hosts на сервере и дополнительно настроить доступ к gitlab registry.
Запишем в файл /etc/rancher/k3s/registries.yaml
следующий код:
configs:
"gitlab.local:5050":
auth:
username: "<Gitlab Registry Username>"
password: "<password>"
tls:
insecure_skip_verify: true
Здесь "Gitlab Registry Username" - созданная учетная запись в gitlab с доступом к gitlab registry.
На этом настройка локального kubernetes завершена, теперь можно настраивать .gitlab-ci своего приложения. Пушить свои образы в registry, и публиковать свои приложения на своём железе.
P.S. Про безопасность. Здесь важно отметить, что если вы собираетесь делать что-то похожее, то не стоит светить своим реальным IP, либо делать это очень аккуратно на свой страх и риск. По хорошему,- это заказать какой-нибудь сетевой балансировщик с проксированием на свой белый IP.