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

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

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

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

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

iTip+

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

让我们开始吧 🚀

1. 获取远程服务器

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

iTip+

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

iTip+

通过专用用户在节点上运行 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 连接到节点服务器。由于本教程我们只处理单个服务器,我们需要最初手动连接到它,以验证连通性。

iTip+

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

ssh -i location/to/keyfile username@server_ip 
iTip+

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

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

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

iWarning+

如果没有设置正确的 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
iTip+

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

iWarning+

请记住,不要将您的 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. 创建随附的角色

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

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 }}"
iTip+

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

systemctl status jenkins

6. 部署您的 playbook

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

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

您可以选择以多种不同的方式为这些变量提供值。您可以在运行时提供它们,在这种情况下,您将使用以下命令部署您的 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 服务器!