Obi Madu 的博客
返回所有文章
InfrastructureDevOpsProjects

通过 Ansible 将 Jenkins 自动部署到远程服务器(带有免费 SSL)(操作指南)

了解如何使用 Ansible 自动部署自托管的 Jenkins 服务器,并配有免费的自动续订 SSL 证书。

通过 Ansible 将 Jenkins 自动部署到远程服务器(带有免费 SSL)(操作指南)

Jenkins 是目前最流行的 CI/CD(持续集成和持续部署)工具之一。它在技术社区中广受喜爱,因为它是免费、开源且自托管的。您可能有很多原因想要部署 Jenkins 服务器,例如构建个人项目、练习使用该软件、用于公司生产用途等。 无论出于何种原因,有一点是肯定的:使用 Ansible 部署您的服务器将使该过程自动化、可重复、可重用、可版本控制和可共享。今天,我们将逐步了解如何创建一个 Ansible playbook,将 Jenkins 部署到远程服务器,并配有免费的 Letsencrypt SSL 证书(会自动续订)。

我已经将该项目的整个代码库上传到 这里的 Github 上。

让我们开始吧 🚀

1. 获取远程服务器

在服务器上部署 Jenkins 的第一步是获取服务器本身。可以从许多不同的地方配置远程服务器。诸如 DigitalOcean、Google Cloud、AWS 等云提供商提供了市场上最具成本效益的 VPS(虚拟专用服务器)计划。 根据您的需求,您可以手动或通过 IaC(基础设施即代码)从这些提供商中的任何一个配置服务器。

出于本教程的目的,请确保在配置服务器实例时使其能够访问公共互联网(因此需要一个公共 IPv4 地址)。

通过专用用户在节点上运行 ansible 命令被认为是一种最佳实践。为了帮助加快创建具有 Ansible 适当权限的专用用户的过程,请使用以下 userdata 启动脚本来启动您的 VPS。

#cloud-config
ssh_pwauth: false

users:
  - name: ansible
    gecos: Ansible User
    groups: users,admin,wheel
    sudo: ALL=(ALL) NOPASSWD:ALL
    shell: /bin/bash
    lock_passwd: true
    ssh_authorized_keys:
      - "ssh-public-key"

"ssh-public-key" 替换为连接到您服务器的适当的 SSH 公钥。

2. 为 Ansible 进行设置

在深入创建我们的 Playbook 之前,我们需要设置一些东西以确保我们的工作流程能够成功。

2.1 验证与远程服务器的 SSH 连接

Ansible 通过 SSH 连接到节点服务器。由于本教程我们只处理单个服务器,我们需要最初手动连接到它,以验证连通性。

部署 VPS 过程的一部分是为其设置 SSH 访问。无论您在哪里部署 VPS,您都应该能够访问用于与服务器进行 SSH 连接的私钥文件。
使用以下命令启动与服务器的 SSH 连接

ssh -i location/to/keyfile username@server_ip 

请确保将您的 SSH 私钥安全地存储在您的 Ansible 主机上,并记录其位置,因为它将在下一步中用于授予 Ansible 访问您的 VPS 的权限。

2.2 为我们的 Jenkins 域名设置 DNS 记录

为了确保从适当的域名访问您的 Jenkins 服务器,您需要将您的域名指向您服务器的 IP 地址。这可以通过创建 DNS 的 A record 来实现。这可以通过各种不同的方式(通过各种接口)完成,具体取决于负责您域名的域名服务。具体细节超出了本教程的范围。

如果没有设置正确的 DNS 记录,您的 Playbook 将无法为您的 Jenkins 服务器颁发 SSL,因为 Certbot(用于颁发证书的客户端)将无法验证您控制着要为其颁发 SSL 证书的域。这将导致您的部署失败,因此请确保设置适当的 DNS 记录。

2.3 创建 Ansible 配置文件

为了正常工作,Ansible 需要配置一些重要的东西。我们在 ansible.cfg 文件中执行此操作。Ansible 在执行之前会自动查找此文件,以找到其运行所需的重要内容。我们的 ansible.cfg 文件将包含以下内容。

[defaults]
inventory = inventory.txt
private_key_file = key.txt
remote_user = ansible

此文件配置了以下重要内容:

  • 它告诉 Ansible 我们的清单文件(列出我们希望 ansible 管理的所有服务器地址的文件)是一个名为 inventory.txt 的文件,并且在当前目录中找到。
  • 它告诉 ansible,用于主机 SSH 连接的私钥文件是一个名为 key.txt 的文件,同样位于当前目录中。
  • 它配置用于服务器 SSH 连接的用户名 ansible。如果您使用前面提供的 cloud-init 脚本配置了服务器,就会是这种情况。如果没有,请随时将此值更改为您的实际 username

为了保持与此配置一致,您应该将用于连接到服务器的 SSH 私钥文件存储在当前目录中名为 key.txt 的文件中,以便 Ansible 能够找到它。

请记住,不要将您的 key.txt 文件签入版本控制。特别是 Github 上的公共存储库。

验证了与服务器的 SSH 连接、设置了适当的 DNS 记录并创建了配置文件后,您就可以创建您的 Playbook 了。

3. 创建 Playbook

是时候创建您的 Ansible Playbook 了。为了保持我们的解决方案简单和模块化,我们将使用 Ansible 角色 (roles)。以下是达到我们期望结果的步骤摘要:

  • 为 Jenkins 设置 Nginx 代理
  • 为我们的服务器获取 SSL 证书
  • 安装 Jenkins


现在来看代码:

---
- hosts: all
  become: true
  roles:
    - nginx-proxy

- hosts: all
  become: true
  roles:
    - certbot

- hosts: all
  become: true
  roles:
    - jenkins

4. 创建随附的角色

接下来,您需要为工作流的不同方面创建角色。 您的角色的目录结构应如下所示:

tree

4.1 在 nginx-proxy 角色内部

创建一个 tasks/mail.yml 文件

包含以下内容:

- name: Install NginX
  tags: nginx,install
  ansible.builtin.apt:
    name: nginx
    state: latest
    update_cache: true

- name: Enable NginX
  ansible.builtin.service:
    name: nginx
    enabled: true

- name: Config Jenkins Proxy
  ansible.builtin.template:
    src: "jenkins-proxy.j2"
    dest: /etc/nginx/sites-available/jenkins-proxy.conf
    owner: root
    group: root
    mode: 0644
  notify: restart_nginx

- name: Enable Proxy
  ansible.builtin.file:
    src: /etc/nginx/sites-available/jenkins-proxy.conf 
    dest: /etc/nginx/sites-enabled/jenkins-proxy.conf
    state: link
  notify: restart_nginx

创建一个 handlers/mail.yml 文件

包含以下内容:

- name: restart_nginx
  ansible.builtin.service:
    name: nginx
    state: restarted

创建一个 templates/jenkins-proxy.j2 文件

包含以下内容:

server { 

    listen 80; # Port for incoming traffic (e.g., 80 for HTTP, 443 for HTTPS)
    server_name {{ server_name }}; # Your domain name or IP address

    # Location block for handling proxied requests

    location / {
        proxy_pass {{ jenkins_localhost }}; # Upstream server address (e.g., http://127.0.0.1:8080)
        
        # Optional settings:
        
        proxy_set_header Host $host; # Preserve host header for upstream server
        proxy_set_header X-Real-IP $remote_addr; # Forward client IP address
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # Forward proxy chain

        # Additional settings as needed (e.g., caching, rewrites)
    }

}

4.2 在 certbot 角色内部

创建一个 tasks/mail.yml 文件

包含以下内容:

- name: Install Snapd
  ansible.builtin.apt:
    name: snapd
    state: latest

- name: Install Certbot
  community.general.snap:
    name: certbot
    classic: true
    state: present

- name: Create symlink    
  ansible.builtin.file:
    src: /snap/bin/certbot 
    dest: /usr/bin/certbot
    state: link

- name: Run certbot
  ansible.builtin.shell: 
    cmd: certbot --nginx -n --agree-tos --email {{ server_email }} --domains {{ server_name }}

4.3 在 jenkins 角色内部

创建一个 tasks/mail.yml 文件

包含以下内容:

- name: Install JDK
  ansible.builtin.apt:
    pkg:
      - fontconfig
      - openjdk-17-jre

- name: Get Jenkins Repo Key
  ansible.builtin.get_url:
    url: https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key
    dest: /usr/share/keyrings/jenkins-keyring.asc

- name: Set Jenkins Source
  ansible.builtin.lineinfile:
    path: /etc/apt/sources.list.d/jenkins.list
    line: deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] https://pkg.jenkins.io/debian-stable binary/
    create: yes

- name: Install Jenkins
  ansible.builtin.apt:
    name: jenkins
    state: present
    update_cache: true

- name: Enable Jenkins
  ansible.builtin.service:
    name: jenkins
    enabled: true

5. 配置 Jenkins 调试输出

在您第一次设置 Jenkins 服务器时,为了开始使用 Web UI,您必须从 Jenkins 服务器上的一个文件中检索一个密钥,以证明您控制着该服务器。我们可以检索这个密钥,并通过在我们的 role/jenkins/tasks/main.yml 文件中添加以下行,让 Ansible 将其输出给我们:

- name: Check Jenkins Status
  ansible.builtin.shell:
    cmd: systemctl status jenkins
  register: check_jens

- name: Debug
  debug:
    msg: "{{ check_jens.stdout_lines }}"

此添加将打印以下命令的值:

systemctl status jenkins

6. 部署您的 playbook

这就是您部署 Playbook 并让 Jenkins 为您自动设置的地方。要部署您的 Playbook,您必须为我们角色中定义的 3 个变量提供适当的值。

  • {{jenkins_localhost}} 变量指向 Jenkins 的 localhost 地址。这通常是 http://localhost:8080
  • {{server_name}} 变量提供了要访问 Jenkins 服务器的域名。这是您之前为其设置 DNS 记录的域。
  • {{server_email}} 变量提供了服务器管理员的电子邮件地址(这是必需的)。

您可以选择以多种不同的方式为这些变量提供值。您可以在运行时提供它们,在这种情况下,您将使用以下命令部署您的 Playbook:

ansible-playbook --extra-vars "server_name=domain-name jenkins_localhost=http://127.0.0.1:8080 
server_email=email" playbook.yml 

domain-nameemail 替换为适当的值。

下面是一个例子:

ansible-playbook --extra-vars "server_name=jen.obimadu.pro 
jenkins_localhost=http://127.0.0.1:8080 
server_email=hello@obimadu.pro" playbook.yml

有关提供变量值的其他方法,请访问 Using Variables

就是这样 🎉 🎉 您现在拥有一种完全自动化的方式来部署(和/或重新部署)您的 Jenkins 服务器!