add jenkins
This commit is contained in:
parent
eb3dfbe970
commit
221ab4b432
6
ansible/group_vars/jenkins.yml
Normal file
6
ansible/group_vars/jenkins.yml
Normal file
@ -0,0 +1,6 @@
|
||||
nginx_server_name: jenkins.home.lab.local
|
||||
jenkins_backend: "http://127.0.0.1:8080" # контейнер проброшен наружу на 8080
|
||||
tls_mode: "letsencrypt" # "letsencrypt" | "custom"
|
||||
tls_cert_path: "/etc/ssl/jenkins/fullchain.pem" # для custom
|
||||
tls_key_path: "/etc/ssl/jenkins/privkey.pem" # для custom
|
||||
client_max_body_size: "1g"
|
||||
@ -18,6 +18,8 @@ homelab:
|
||||
ansible_host: 192.168.0.101
|
||||
vpn:
|
||||
ansible_host: vpn.home.lab.local
|
||||
jenkins:
|
||||
ansible_host: jenkins.home.lab.local
|
||||
children:
|
||||
dns:
|
||||
hosts:
|
||||
|
||||
@ -4,3 +4,4 @@
|
||||
become: true
|
||||
roles:
|
||||
- packages
|
||||
- docker
|
||||
|
||||
33
ansible/jenkins.yml
Normal file
33
ansible/jenkins.yml
Normal file
@ -0,0 +1,33 @@
|
||||
---
|
||||
- name: Jenkins in Docker (with JCasC & baked plugins)
|
||||
hosts: jenkins
|
||||
become: true
|
||||
vars:
|
||||
nginx_conf_path: /etc/nginx/sites-available/jenkins.conf
|
||||
nginx_conf_link: /etc/nginx/sites-enabled/jenkins.conf
|
||||
jenkins_version: "lts-jdk17" # можно weekly, но lts стабильнее
|
||||
jenkins_image_name: "jenkins-custom-casc:1.0.0"
|
||||
jenkins_root: "/srv/jenkins"
|
||||
jenkins_data_dir: "{{ jenkins_root }}/data"
|
||||
jenkins_build_dir: "{{ jenkins_root }}/build"
|
||||
jenkins_http_port: 8080
|
||||
jenkins_agent_port: 50000
|
||||
jenkins_admin_user: "admin"
|
||||
# jenkins_admin_password: "ChangeMe_UseVault!" # Хранить в Ansible Vault! - поставил на хосте
|
||||
jenkins_url: "http://{{ ansible_default_ipv4.address }}:{{ jenkins_http_port }}"
|
||||
jenkins_plugins:
|
||||
- configuration-as-code
|
||||
- job-dsl
|
||||
- workflow-aggregator
|
||||
- credentials
|
||||
- credentials-binding
|
||||
- git
|
||||
- github
|
||||
- ssh-credentials
|
||||
- matrix-auth
|
||||
- timestamper
|
||||
- email-ext
|
||||
- ws-cleanup
|
||||
- pipeline-utility-steps
|
||||
roles:
|
||||
- jenkins
|
||||
@ -25,3 +25,4 @@ $TTL 604800
|
||||
229.0 IN PTR libre.home.lab.local. ; 192.168.0.229
|
||||
235.0 IN PTR monitoring.home.lab.local. ; 192.168.0.235
|
||||
226.0 IN PTR wg.home.lab.local. ; 192.168.0.226
|
||||
145.0 IN PTR jenkins.home.lab.local. ; 192.168.0.145
|
||||
|
||||
@ -28,3 +28,4 @@ nas.home.lab.local. IN A 192.168.0.100
|
||||
libre.home.lab.local. IN A 192.168.0.229
|
||||
monitoring.home.lab.local. IN A 192.168.0.235
|
||||
wg.home.lab.local. IN A 192.168.0.226
|
||||
jenkins.home.lab.local. IN A 192.168.0.145
|
||||
|
||||
@ -8,34 +8,50 @@
|
||||
- lsb-release
|
||||
state: present
|
||||
|
||||
- name: Add Docker official GPG key (Debian/Ubuntu)
|
||||
ansible.builtin.apt_key:
|
||||
url: https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg
|
||||
state: present
|
||||
when: ansible_os_family == 'Debian'
|
||||
- name: Ensure docker keyring dir
|
||||
ansible.builtin.file:
|
||||
path: /etc/apt/keyrings
|
||||
state: directory
|
||||
mode: "0755"
|
||||
|
||||
- name: Add Docker repo (Debian/Ubuntu)
|
||||
ansible.builtin.apt_repository:
|
||||
repo: "deb [arch={{ ansible_architecture }}] https://download.docker.com/linux/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable"
|
||||
state: present
|
||||
when: ansible_os_family == 'Debian'
|
||||
- name: Add Docker GPG (dearmored)
|
||||
ansible.builtin.get_url:
|
||||
url: https://download.docker.com/linux/ubuntu/gpg
|
||||
dest: /etc/apt/keyrings/docker.gpg
|
||||
mode: "0644"
|
||||
register: docker_gpg_raw
|
||||
|
||||
- name: Dearmor Docker GPG if needed
|
||||
ansible.builtin.shell: |
|
||||
gpg --dearmor < /etc/apt/keyrings/docker.gpg > /etc/apt/keyrings/docker.gpg.tmp
|
||||
mv /etc/apt/keyrings/docker.gpg.tmp /etc/apt/keyrings/docker.gpg
|
||||
chmod a+r /etc/apt/keyrings/docker.gpg
|
||||
args:
|
||||
creates: /etc/apt/keyrings/docker.gpg.tmp
|
||||
when: docker_gpg_raw is changed
|
||||
|
||||
- name: Map architecture to repo arch
|
||||
ansible.builtin.set_fact:
|
||||
repo_arch: "{{ 'arm64' if ansible_architecture in ['aarch64','arm64'] else 'amd64' }}"
|
||||
|
||||
- name: Add Docker repo (correct arch + signed-by)
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/apt/sources.list.d/docker.list
|
||||
mode: "0644"
|
||||
content: |
|
||||
deb [arch={{ repo_arch }} signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable
|
||||
|
||||
- name: apt update
|
||||
ansible.builtin.apt:
|
||||
update_cache: true
|
||||
|
||||
- name: Install Docker Engine & Compose plugin
|
||||
ansible.builtin.package:
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- docker-ce
|
||||
- docker-ce-cli
|
||||
- containerd.io
|
||||
- docker-buildx-plugin
|
||||
- docker-compose-plugin
|
||||
update_cache: true
|
||||
state: present
|
||||
|
||||
- name: Install Docker Python SDK for Ansible modules
|
||||
ansible.builtin.pip:
|
||||
name: docker
|
||||
|
||||
- name: Ensure docker service running
|
||||
ansible.builtin.service:
|
||||
name: docker
|
||||
state: started
|
||||
enabled: true
|
||||
|
||||
4
ansible/roles/jenkins/handlers/main.yml
Normal file
4
ansible/roles/jenkins/handlers/main.yml
Normal file
@ -0,0 +1,4 @@
|
||||
- name: reload nginx
|
||||
systemd:
|
||||
name: nginx
|
||||
state: reloaded
|
||||
63
ansible/roles/jenkins/tasks/main.yml
Normal file
63
ansible/roles/jenkins/tasks/main.yml
Normal file
@ -0,0 +1,63 @@
|
||||
- name: Create directories
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
mode: "0755"
|
||||
loop:
|
||||
- "{{ jenkins_root }}"
|
||||
- "{{ jenkins_build_dir }}"
|
||||
- "{{ jenkins_data_dir }}"
|
||||
|
||||
- name: Template plugins list
|
||||
template:
|
||||
src: templates/plugins.txt.j2
|
||||
dest: "{{ jenkins_build_dir }}/plugins.txt"
|
||||
mode: "0644"
|
||||
|
||||
- name: Template Dockerfile
|
||||
template:
|
||||
src: templates/Dockerfile.j2
|
||||
dest: "{{ jenkins_build_dir }}/Dockerfile"
|
||||
mode: "0644"
|
||||
|
||||
- name: Build custom Jenkins image (plugins baked in)
|
||||
community.docker.docker_image:
|
||||
name: "{{ jenkins_image_name }}"
|
||||
build:
|
||||
path: "{{ jenkins_build_dir }}"
|
||||
source: build
|
||||
register: build_img
|
||||
|
||||
- name: Template JCasC config
|
||||
template:
|
||||
src: templates/jenkins-casc.yaml.j2
|
||||
dest: "{{ jenkins_data_dir }}/casc.yaml"
|
||||
mode: "0640"
|
||||
|
||||
- name: Ensure ownership for Jenkins data (uid/gid 1000)
|
||||
file:
|
||||
path: "{{ jenkins_data_dir }}"
|
||||
state: directory
|
||||
owner: "1000"
|
||||
group: "1000"
|
||||
recurse: true
|
||||
|
||||
- name: Template docker-compose.yaml
|
||||
template:
|
||||
src: templates/docker-compose.yaml.j2
|
||||
dest: "{{ jenkins_root }}/docker-compose.yaml"
|
||||
mode: "0644"
|
||||
|
||||
- name: Up jenkins stack
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ jenkins_root }}"
|
||||
files: ["docker-compose.yaml"]
|
||||
state: present
|
||||
register: dc
|
||||
|
||||
- name: Wait for Jenkins HTTP
|
||||
wait_for:
|
||||
host: 127.0.0.1
|
||||
port: "{{ jenkins_http_port }}"
|
||||
delay: 3
|
||||
timeout: 180
|
||||
6
ansible/roles/jenkins/templates/Dockerfile.j2
Normal file
6
ansible/roles/jenkins/templates/Dockerfile.j2
Normal file
@ -0,0 +1,6 @@
|
||||
FROM jenkins/jenkins:{{ jenkins_version }}
|
||||
USER root
|
||||
# Ускоряем установку плагинов и делаем образ детерминированным
|
||||
COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
|
||||
RUN jenkins-plugin-cli --plugin-file /usr/share/jenkins/ref/plugins.txt
|
||||
USER jenkins
|
||||
23
ansible/roles/jenkins/templates/docker-compose.yaml.j2
Normal file
23
ansible/roles/jenkins/templates/docker-compose.yaml.j2
Normal file
@ -0,0 +1,23 @@
|
||||
services:
|
||||
jenkins:
|
||||
image: "{{ jenkins_image_name }}"
|
||||
container_name: jenkins
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "{{ jenkins_http_port }}:8080"
|
||||
- "{{ jenkins_agent_port }}:50000"
|
||||
environment:
|
||||
JAVA_OPTS: "-Djenkins.install.runSetupWizard=false -Dcasc.jenkins.config=/var/jenkins_home/casc.yaml"
|
||||
JENKINS_ADMIN_ID: "{{ jenkins_admin_user }}"
|
||||
JENKINS_ADMIN_PASSWORD: ${JENKINS_ADMIN_PASSWORD}
|
||||
volumes:
|
||||
- "{{ jenkins_data_dir }}:/var/jenkins_home"
|
||||
# Если нужно, чтобы pipeline-ы запускали Docker на хосте — расскомментируйте:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
# healthcheck, чтобы Ansible/оркестратор видел состояние
|
||||
healthcheck:
|
||||
test: ["CMD", "bash", "-lc", "curl -fsSL http://127.0.0.1:8080/login || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
62
ansible/roles/jenkins/templates/jenkins-casc.yaml.j2
Normal file
62
ansible/roles/jenkins/templates/jenkins-casc.yaml.j2
Normal file
@ -0,0 +1,62 @@
|
||||
jenkins:
|
||||
systemMessage: "Managed by Ansible + JCasC. Do not edit via UI."
|
||||
numExecutors: 2
|
||||
mode: NORMAL
|
||||
|
||||
# ✅ Перенесено в jenkins.*
|
||||
crumbIssuer:
|
||||
standard:
|
||||
excludeClientIPFromCrumb: false
|
||||
|
||||
# ✅ Перенесено в jenkins.*
|
||||
securityRealm:
|
||||
local:
|
||||
allowsSignup: false
|
||||
users:
|
||||
- id: "${JENKINS_ADMIN_ID}"
|
||||
password: "${JENKINS_ADMIN_PASSWORD}"
|
||||
|
||||
# ✅ Современный matrix-auth
|
||||
authorizationStrategy:
|
||||
globalMatrix:
|
||||
grantedPermissions:
|
||||
- "Overall/Administer:${JENKINS_ADMIN_ID}"
|
||||
- "Overall/Read:authenticated"
|
||||
|
||||
unclassified:
|
||||
# ✅ Разрешённый ключ
|
||||
location:
|
||||
url: "{{ jenkins_url }}"
|
||||
# ✅ У плагина timestamper имя узла — 'timestamper'
|
||||
timestamper:
|
||||
systemTimeFormat: "yyyy-MM-dd HH:mm:ss"
|
||||
elapsedTimeFormat: "'+'HH:mm:ss"
|
||||
|
||||
tool:
|
||||
git:
|
||||
installations:
|
||||
- name: "Default"
|
||||
home: "/usr/bin/git"
|
||||
|
||||
jobs:
|
||||
- script: |
|
||||
pipelineJob('hello-pipeline') {
|
||||
definition {
|
||||
cps {
|
||||
script('''\
|
||||
pipeline {
|
||||
agent any
|
||||
stages {
|
||||
stage('Hello') {
|
||||
steps {
|
||||
echo "It works on ${env.NODE_NAME}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
'''.stripIndent())
|
||||
sandbox(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
73
ansible/roles/jenkins/templates/nginx-jenkins-https.conf.j2
Normal file
73
ansible/roles/jenkins/templates/nginx-jenkins-https.conf.j2
Normal file
@ -0,0 +1,73 @@
|
||||
# HTTP → HTTPS редирект
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name {{ nginx_server_name }};
|
||||
|
||||
# ACME challenge (если включен LE)
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
root /var/www/jenkins;
|
||||
}
|
||||
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
# HTTPS ↔ Jenkins (reverse proxy)
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
server_name {{ nginx_server_name }};
|
||||
|
||||
{% if tls_mode == 'letsencrypt' %}
|
||||
ssl_certificate /etc/letsencrypt/live/{{ nginx_server_name }}/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/{{ nginx_server_name }}/privkey.pem;
|
||||
{% else %}
|
||||
ssl_certificate {{ tls_cert_path }};
|
||||
ssl_certificate_key {{ tls_key_path }};
|
||||
{% endif %}
|
||||
|
||||
# Базовая TLS-настройка
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:MozSSL:10m;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
# (Опционально) HSTS — включай, если домен всегда по HTTPS
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
|
||||
# Размер артефактов, long-running шаги
|
||||
client_max_body_size {{ client_max_body_size }};
|
||||
proxy_read_timeout 3600s;
|
||||
proxy_send_timeout 3600s;
|
||||
|
||||
# Проксирование в Jenkins-контейнер
|
||||
location / {
|
||||
proxy_pass {{ jenkins_backend }};
|
||||
proxy_http_version 1.1;
|
||||
|
||||
# WebSocket/HTTP/1.1
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
|
||||
# Проброс хостов/протоколов/адресов
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_set_header X-Forwarded-Port 443;
|
||||
|
||||
# Убираем буферизацию, Jenkins любит стримить логи билда
|
||||
proxy_buffering off;
|
||||
}
|
||||
|
||||
# Вспомогательное: корректная переменная для upgrade
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
access_log /var/log/nginx/jenkins.access.log;
|
||||
error_log /var/log/nginx/jenkins.error.log;
|
||||
}
|
||||
3
ansible/roles/jenkins/templates/plugins.txt.j2
Normal file
3
ansible/roles/jenkins/templates/plugins.txt.j2
Normal file
@ -0,0 +1,3 @@
|
||||
{% for p in jenkins_plugins -%}
|
||||
{{ p }}
|
||||
{% endfor -%}
|
||||
7
ansible/roles/jenkins/vars/main.yml
Normal file
7
ansible/roles/jenkins/vars/main.yml
Normal file
@ -0,0 +1,7 @@
|
||||
nginx_server_name: jenkins.home.lab.local
|
||||
jenkins_backend: "http://127.0.0.1:8080" # контейнер проброшен наружу на 8080
|
||||
tls_mode: "letsencrypt" # "letsencrypt" | "custom"
|
||||
tls_cert_path: "/etc/ssl/jenkins/fullchain.pem" # для custom
|
||||
tls_key_path: "/etc/ssl/jenkins/privkey.pem" # для custom
|
||||
client_max_body_size: "1g"
|
||||
email: oleg.vodyanov91@gmail.com
|
||||
Loading…
x
Reference in New Issue
Block a user