Всё началось с того, что в 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.
