From 04d0e2ae314291b06bab50d6b9424af72359ad59 Mon Sep 17 00:00:00 2001 From: emil28092005 Date: Fri, 16 Jan 2026 23:17:44 +0300 Subject: [PATCH] remake architecture. --- .gitignore | 4 +- Jenkinsfile | 34 +++++--- README.md | 0 cmd/server/main.go | 7 +- deploy/shagram/compose.yaml | 24 ++++++ deploy/shagram/nginx/certs/.gitkeep | 0 deploy/shagram/nginx/certs/README.md | 34 ++++++++ .../shagram/nginx}/conf.d/default.conf | 0 docker-compose-jenkins.yml | 20 ----- docker-compose.yml | 24 ------ infra/jenkins/README.md | 78 +++++++++++++++++++ infra/jenkins/compose.yaml | 31 ++++++++ nginx/certs/cert.pem | 22 ------ nginx/certs/key.pem | 28 ------- 14 files changed, 198 insertions(+), 108 deletions(-) create mode 100644 README.md create mode 100644 deploy/shagram/compose.yaml create mode 100644 deploy/shagram/nginx/certs/.gitkeep create mode 100644 deploy/shagram/nginx/certs/README.md rename {nginx => deploy/shagram/nginx}/conf.d/default.conf (100%) delete mode 100644 docker-compose-jenkins.yml delete mode 100644 docker-compose.yml create mode 100644 infra/jenkins/README.md create mode 100644 infra/jenkins/compose.yaml delete mode 100644 nginx/certs/cert.pem delete mode 100644 nginx/certs/key.pem diff --git a/.gitignore b/.gitignore index cee86b7..f1b5d94 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ project_context.txt -shagram.db \ No newline at end of file +shagram.db +deploy/shagram/nginx/certs/*.pem +deploy/shagram/.env \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile index 79c8d81..a67643a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,35 +1,45 @@ pipeline{ - agent any + agent { label 'docker' } options { skipDefaultCheckout() } + environment { + SRC_DIR = "/opt/shagram/src/shagram" + DEPLOY_DIR = "/opt/shagram/deploy/shagram" + IMAGE_NAME = "shagram" + } stages{ stage('Checkout') { steps { - deleteDir() - git url: 'https://github.com/emil28092005/shagram.git', branch: 'main' + dir(env.SRC_DIR) { + deleteDir() + git url: 'https://github.com/emil28092005/shagram.git', branch: 'main' + } } } stage('Build') { steps { - echo 'Building shagram...' - sh 'docker build -t shagram-shagram:latest .' + dir(env.SRC_DIR) { + echo 'Building shagram...' + sh 'docker build -t ${IMAGE_NAME}:${GIT_COMMIT} .' + + } } } stage('Test') { steps { echo 'Testing...' - sh 'docker run --rm shagram-shagram:latest sqlite3 /app/shagram.db "SELECT 1;" || true' + sh 'docker run --rm ${IMAGE_NAME}:${GIT_COMMIT} sqlite3 --version' } } stage('Deploy') { steps { - echo 'Deploying...' - sh ''' - docker compose down || true - docker compose up -d - docker compose ps - ''' + dir(env.DEPLOY_DIR) { + echo 'Deploying...' + sh 'printf "APP_IMAGE=%s\\n" "${IMAGE_NAME}:${GIT_COMMIT}" > .env' + sh 'docker compose up -d' + sh 'docker compose ps' + } } } } diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/cmd/server/main.go b/cmd/server/main.go index 253c1fc..dd484c1 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -3,6 +3,7 @@ package main import ( "log" "net/http" + "os" "shagram/internal/api" "shagram/internal/db" "shagram/internal/models" @@ -12,7 +13,11 @@ import ( ) func main() { - database, err := db.NewDB("/app/data/shagram.db") + dbPath := os.Getenv("DATABASE_PATH") + if dbPath == "" { + dbPath = "/app/data/shagram.db" + } + database, err := db.NewDB(dbPath) if err != nil { log.Fatal(err) } diff --git a/deploy/shagram/compose.yaml b/deploy/shagram/compose.yaml new file mode 100644 index 0000000..a8e2b9c --- /dev/null +++ b/deploy/shagram/compose.yaml @@ -0,0 +1,24 @@ +services: + shagram: + image: ${APP_IMAGE} + container_name: shagram-app + environment: + - DATABASE_PATH=/app/data/shagram.db + volumes: + - shagram_data:/app/data + expose: + - "8080" + + nginx: + image: nginx:alpine + container_name: shagram-nginx + ports: + - "80:80" + - "443:443" + volumes: + - ./nginx/conf.d:/etc/nginx/conf.d:ro + - ./nginx/certs:/etc/nginx/certs:ro + depends_on: + - shagram +volumes: + shagram_data: \ No newline at end of file diff --git a/deploy/shagram/nginx/certs/.gitkeep b/deploy/shagram/nginx/certs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/deploy/shagram/nginx/certs/README.md b/deploy/shagram/nginx/certs/README.md new file mode 100644 index 0000000..10e1e0c --- /dev/null +++ b/deploy/shagram/nginx/certs/README.md @@ -0,0 +1,34 @@ +# TLS Certificates for Nginx (Development / Self-Signed) + +In production, TLS certificates are typically issued by a trusted Certificate Authority (for example, via Let’s Encrypt). +For local development and demo environments, a self-signed certificate can be used. + +## Generate a self-signed certificate (Linux/macOS) +From the repository root: + +```bash +mkdir -p deploy/shagram/nginx/certs + +openssl req -x509 -newkey rsa:4096 \ + -keyout deploy/shagram/nginx/certs/key.pem \ + -out deploy/shagram/nginx/certs/cert.pem \ + -sha256 -days 365 -nodes \ + -subj "/C=RU/ST=Moscow/L=Korolyov/O=Shagram/CN=localhost" +``` + +## Verify +```bash +openssl x509 -in deploy/shagram/nginx/certs/cert.pem -noout -text | head +``` + +## Usage +The Nginx configuration expects: +- `deploy/shagram/nginx/certs/cert.pem` +- `deploy/shagram/nginx/certs/key.pem` + +Start the deployment: + +```bash +cd deploy/shagram +docker compose up -d +``` diff --git a/nginx/conf.d/default.conf b/deploy/shagram/nginx/conf.d/default.conf similarity index 100% rename from nginx/conf.d/default.conf rename to deploy/shagram/nginx/conf.d/default.conf diff --git a/docker-compose-jenkins.yml b/docker-compose-jenkins.yml deleted file mode 100644 index 1296a79..0000000 --- a/docker-compose-jenkins.yml +++ /dev/null @@ -1,20 +0,0 @@ -services: - jenkins: - image: jenkins/jenkins:lts-jdk17 - container_name: jenkins - ports: - - "8080:8080" - - "50000:50000" - volumes: - - /var/run/docker.sock:/var/run/docker.sock - - /usr/bin/docker:/usr/bin/docker - - /usr/libexec/docker/cli-plugins:/usr/libexec/docker/cli-plugins:ro - - jenkins_home:/var/jenkins_home - - /opt/shagram:/workspace - environment: - - DOCKER_HOST=unix:///var/run/docker.sock - user: root - restart: unless-stopped - -volumes: - jenkins_home: diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index b84136f..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,24 +0,0 @@ -services: - shagram: - build: . - ports: - - "8080" - volumes: - - ./data:/app/data - - ./static:/app/static - - ./migrations:/app/migrations - environment: - - DATABASE_PATH=/app/shagram.db - container_name: shagram-app - - nginx: - image: nginx:alpine - ports: - - "80:80" - - "443:443" - volumes: - - ./nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf - - ./nginx/certs:/etc/nginx/certs - depends_on: - - shagram - container_name: shagram-nginx \ No newline at end of file diff --git a/infra/jenkins/README.md b/infra/jenkins/README.md new file mode 100644 index 0000000..a5c8dfc --- /dev/null +++ b/infra/jenkins/README.md @@ -0,0 +1,78 @@ +# Jenkins (Controller + Docker Agent) Setup (Docker Compose) + +This directory contains a minimal Jenkins setup using a dedicated **controller** and a separate inbound **agent** intended for Docker-based workloads. + +The goal is to keep the controller responsible for orchestration and configuration, while all builds run on the agent labeled `docker`. + +## Prerequisites +- Docker Engine installed on the host +- Docker Compose available as `docker compose` +- A host directory `/opt/shagram` (used by pipelines as a shared location for source code and deployment files) + +## Start Jenkins +From the repository root: + +```bash +cd infra/jenkins +docker compose up -d +docker compose ps +``` + +Jenkins UI will be available at: + +- http://:8080 + +### Initial admin password +Retrieve the initial password with: + +```bash +docker exec -it jenkins-controller cat /var/jenkins_home/secrets/initialAdminPassword +``` + +## Disable builds on the built-in node (Executors = 0) +To ensure builds do not run on the controller: + +1. Open Jenkins UI +2. Go to: **Manage Jenkins → Manage Nodes and Clouds** +3. Open **Built-In Node → Configure** +4. Set **Number of executors** to `0` +5. Save + +## Create an inbound agent node (docker-agent) +Create a dedicated node for running pipelines: + +1. Go to: **Manage Jenkins → Manage Nodes and Clouds → New Node** +2. Set: + - **Node name**: `docker-agent` + - **Type**: Permanent Agent + - **Remote root directory**: `/home/jenkins/agent` + - **Labels**: `docker` + - **Usage**: Only build jobs with label expressions matching this node +3. Save + +After saving, open the agent page: + +- **Manage Nodes and Clouds → docker-agent** + +On that page, Jenkins provides the inbound connection details, including the **secret** required by the inbound agent container. + +## Configure the agent secret in Compose +Edit `infra/jenkins/compose.yaml` and replace: + +- `JENKINS_SECRET=__PASTE_ME__` + +with the real secret value shown on the `docker-agent` node page. + +Restart only the agent container: + +```bash +docker compose up -d --force-recreate jenkins-agent-docker +docker logs -f jenkins-agent-docker +``` + +## Verification +- In Jenkins UI: **Manage Nodes and Clouds**, the node `docker-agent` should be **Online** +- Any pipeline using `agent { label 'docker' }` should execute on this agent + +## Security note +The Docker agent container mounts `/var/run/docker.sock`, which effectively grants high-level control over the Docker host. Use this setup only in trusted environments and limit access to Jenkins accordingly. diff --git a/infra/jenkins/compose.yaml b/infra/jenkins/compose.yaml new file mode 100644 index 0000000..110e993 --- /dev/null +++ b/infra/jenkins/compose.yaml @@ -0,0 +1,31 @@ +services: + jenkins-controller: + image: jenkins/jenkins:lts-jdk17 + container_name: jenkins-controller + ports: + - "8080:8080" + volumes: + - jenkins_home:/var/jenkins_home + restart: unless-stopped + + jenkins-agent-docker: + image: jenkins/inbound-agent:latest-jdk17 + container_name: jenkins-agent-docker + environment: + - JENKINS_URL=http://jenkins-controller:8080 + - JENKINS_AGENT_NAME=docker-agent + - JENKINS_SECRET=__PASTE_ME__ + - AGENT_WORKDIR=/home/jenkins/agent + volumes: + - agent_workdir:/home/jenkins/agent + - /var/run/docker.sock:/var/run/docker.sock + - /usr/bin/docker:/usr/bin/docker + - /usr/libexec/docker/cli-plugins:/usr/libexec/docker/cli-plugins:ro + - /opt/shagram:/opt/shagram + restart: unless-stopped + depends_on: + - jenkins-controller + +volumes: + jenkins_home: + agent_workdir: diff --git a/nginx/certs/cert.pem b/nginx/certs/cert.pem deleted file mode 100644 index d8cd503..0000000 --- a/nginx/certs/cert.pem +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDjzCCAnegAwIBAgIUG1Qc10mXTy5+Zuh1COAK6fqAl34wDQYJKoZIhvcNAQEL -BQAwVzELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vc2NvdzERMA8GA1UEBwwIS29y -b2x5b3YxEDAOBgNVBAoMB1NoYWdyYW0xEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0y -NjAxMTQwMTMxNDhaFw0yNzAxMTQwMTMxNDhaMFcxCzAJBgNVBAYTAlJVMQ8wDQYD -VQQIDAZNb3Njb3cxETAPBgNVBAcMCEtvcm9seW92MRAwDgYDVQQKDAdTaGFncmFt -MRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQDLOB4WybryG6Cc4yU+2PPrLiM/tt15HMVp0TgcA277vofYFd90IArihbmG -KEaKYyZplUzxk55RRNS6BaAroZb0AWEg8cOid83gbnuKKaIUhjz/CDADPnnRWynb -PHjVuvIBtPLgyunbtB6U7a6JLP2nA8XaTcDFtLrhy8PTKFZ9fLRBXzxW8ZvNnL4i -FSLQYe851dOfJ1m0HwA/meK8QWfYn01O8zprleSMo+HPIudRR6ySnx/Cy3LuAcqM -sjttf6EFWs9XTiAOIbKC4M8VbOrfZjXFz45ljD0tZNziJ2g61lmdJAV8ElwZ6SDP -fGTwGjWj5Qx9Lg7qdFqjVyE0QFBJAgMBAAGjUzBRMB0GA1UdDgQWBBSd7S5Xngb4 -9eeBbmTCslblkWClRDAfBgNVHSMEGDAWgBSd7S5Xngb49eeBbmTCslblkWClRDAP -BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA8Lx0PAhfYRuRYuQxV -EyU4pmQ6JuAPl3gxVKHY6bFGMYooSRr5Nw/YulfPucxTKHtVlgY/l0kwofmTUh3B -Df1tulFCCmBW4zbl6cHd7TVSEJBkV7R9AqAC49ni8mVhmo3uPuARFa+mR8ATrF4y -LWlO/2n7F5g+093CqOG3b4O76PlqAl6L/z/Z+UBoMVEyiPgfxAztucsBn7oOaQwG -g6ohX2kosC2uRsc1bAofHWW0u3tFY0i6oiI7XPF9REuWJOiDlN2PsDMXhSG5xeLj -e7LUOQsNXB5deAfUFxbtEDCnEDzyp+GxXwZ0iPsJOzm2ccL6XdDzucCuR/NtuhGf -KwpD ------END CERTIFICATE----- diff --git a/nginx/certs/key.pem b/nginx/certs/key.pem deleted file mode 100644 index 0b11e77..0000000 --- a/nginx/certs/key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDLOB4WybryG6Cc -4yU+2PPrLiM/tt15HMVp0TgcA277vofYFd90IArihbmGKEaKYyZplUzxk55RRNS6 -BaAroZb0AWEg8cOid83gbnuKKaIUhjz/CDADPnnRWynbPHjVuvIBtPLgyunbtB6U -7a6JLP2nA8XaTcDFtLrhy8PTKFZ9fLRBXzxW8ZvNnL4iFSLQYe851dOfJ1m0HwA/ -meK8QWfYn01O8zprleSMo+HPIudRR6ySnx/Cy3LuAcqMsjttf6EFWs9XTiAOIbKC -4M8VbOrfZjXFz45ljD0tZNziJ2g61lmdJAV8ElwZ6SDPfGTwGjWj5Qx9Lg7qdFqj -VyE0QFBJAgMBAAECggEALgf0UtOXd6M35omSBHIWkBknjVVRxc71TYKBS+EgOMA/ -23ua3Z4rcQN60k9ZqRuL1iMmJls6Y2yspcVD8lYcEAGm+1Qf7PNnrBRCgflrt+vv -MZJsc7OpWrlkWf9Q3JLHogjXcgEsZyJdwfyzielpvDS/0nLFvVKyeRZTcUdEDhCz -MoY3tqcZVwq1k+CsW5Z8C1DZaEwgwhEXNGPgfX7R86FSNwlNmcTKJG/YHb9xBA84 -O109pfe9PsQnYB9Lw+CNPHl1v6wIMRlVZZMFPevBJq+r9d8iN6dsX7c4oR8SXDDS -4Shux9RNE8XyD6HOTK+QuEvJmZmPIFjnlVZIsVkpHQKBgQD5bfeh7En+VPdHFGTg -+0o1ZSYrfvErak8zP7DoLZF4EY6CK20uZ8ou09ebWXZQfC37PliOSMJyDG70PuXc -Rh/TfnUPkPbmyRrvQi+MAsIjCEYGk2iiMQvSVs099AB6oAQetyPm2AcT4HeGNaLM -m1gurXTCelV0yT7oL7IhI6AqRQKBgQDQkoenTQ1nnvA4ghN253c+mbJWvTX+lbo9 -WicOAxmA9gp/VN7NErXbgr5FcMwPtT+yLDqDgSjLp2T9ClYt/laWcO/KYwrnP9o5 -DTeSB+biEAd3GHJLWJApY/dmFZey5uza+hXvlTdVCUgvFJYGgHw/Dg5E+jvUwrNT -MNN/OnpQNQKBgAtxxz3vuIlp3pqtTd+gyAvhIzo1rd0fGJkyX+yXQqhurco9MdpC -Ot2hLLBdD3er6vQvLSMCJaHT/jdIt4U+1nD+yWI4dYurSIgX0lSrP7sZwxTEKLXg -aDlzcCFak7cMpoO+RXBvEwwPbYyD439d1VL29HeD423jWfaPUa4Bk3S9AoGAWGdj -PBQ6tEr3wtvPaDyfnFcE8iLsueW4tLx7hULnEnQ26tWMQhvGHS6De2dd9uJ6Bwkc -HBUot3lSIra45HHDPazM1lm4i1/THQ9vGGRlBjiJEX+5Ihp9sC2A9TH9xISArCgI -GC6E73QptlrhZAwdnZRVlAMETR/hZkdxvaGJqmkCgYEAzHpqhLMFwOOvDr5Ya2DW -5IGSCohsNBRvPKLSXlMIT1yMfRStsp5qQrZq2Oj2xXX7Jk3jf+1lU3ZQ5O6bI6br -9MhrVKu6qI8YS3OtSDPAUOzPw1zu4yaKyCO0eNghY51PTZd3A3JA8Uh9Si7OCryD -iHnkhUQ1iasZLdnubyVUuh0= ------END PRIVATE KEY-----