如何使用 Ansible 通过 SSH 设置 Git 服务器

Git 是开源社区中最广泛部署的版本控制系统。本系列文章的第 2 部分着眼于在您的 LAN 上使用 Ansible 设置 Git。
523 位读者喜欢这篇文章。
9 Lessons from 25 Years of Linux Kernel development

Internet Archive Book Images。Opensource.com 修改。CC BY-SA 4.0

在本系列的 第 1 部分 中,我描述了 Ansible 远程管理工具的基础知识。我设置了环境,在控制机器上安装了 Ansible 包,设置了基本清单,并演示了基本 playbook。我不需要备份这些简单且易于重现的 playbook,但是随着这些 playbook 开始充当我的实验室环境的蓝图和文档,我需要考虑如何备份它们。

在本系列的第二部分中,我原计划介绍 Copysystemdserviceaptyumvirtuser 模块,但为了保持重点突出和切中要点,我决定将大部分讨论移到后续文章中,并探讨另一种使用 Ansible 的方式:设置用于版本控制的 Git SSH 服务器。

版本控制的必要性

版本控制是一种跟踪对您可能处理的文件、一系列文件或项目所做更改的方法。通常,版本控制系统会存储基本信息,例如

  • 哪个用户进行了更改,
  • 何时进行了更改,以及
  • 更改了哪些文件。

这可能是至关重要的信息,特别是当与恢复更改的能力相结合时,从长远来看,它将为您节省很多麻烦。

那么有哪些可用的选项呢?最流行的 版本控制系统 是 Mercurial、Subversion 和 Git。每种系统的优缺点超出了本系列的范围,但 Git 已成为开源社区中最广泛部署的源代码控制系统。有几个流行的选项可供考虑:Stash/Bitbucket(来自 Atlassian)、GitHub、GitLab 和带有 Git 的 Perforce(以及许多其他企业实现)。它们都具有友好的 Web 前端,并且适用于团队协作;但是,它们的设置也复杂得多。

但是,Git 确实提供了另一个优势。您可以在 LAN 上通过安全 Shell (SSH) 运行 Git 服务器,这设置和管理起来不那么复杂,而且对硬件资源的要求也相当低。

Git SSH 服务器要求

Git SSH 服务器的硬件要求非常低。事实上,没有提供服务器规格;任何具有网络连接且运行能够安装 Git 的 Linux 发行版的机器都可以提供 Git SSH 服务。

在软件方面,Git 服务器需要以下设置

  1. 在将充当 Git SSH 服务器的机器上安装 Git 包
  2. 安装并配置 SSH 以允许通过 SSH 密钥进行连接
  3. Git SSH 服务器上的专用用户,该用户通过 SSH 提供对服务器的访问(按照惯例,这通常是 git 用户)
  4. 在前面步骤中专用用户的 authorized_keys 文件中安装所有客户端的 SSH 公钥

我的 Git SSH 服务器是一台 CentOS 7.3 VM,在 /home 中有 26GB 的空间,Git 仓库将驻留在此处。

使用 Ansible 设置 Git 服务器

对于家庭或实验室环境,使用 Ansible 设置 Git SSH 服务器可能有点大材小用,但它确实服务于两个重要的功能

  1. 它提供了一个扩展一些更高级 Ansible 主题的途径。
  2. 它提供了一组可重复的步骤,这些步骤(由于 Ansible 的性质)是自我记录的。这意味着 Git SSH 服务器的复制应该是微不足道的。

第一步是将您的 SSH 密钥从 Ansible 控制机器复制到 Git SSH 服务器。回顾一下,可以使用 ssh-keygen 命令生成 SSH 密钥。一旦创建了 SSH 密钥,就可以通过 ssh-copy-id user@host 命令将其推送到远程主机。

下一步是安装 Git 包。示例 1 演示了一个简单的 playbook 来完成此任务。

示例 1:包安装 playbook

- hosts: "{{ hostname }}"
  gather_facts: False
  vars:
    - packages: ["git", "nmap"]
  tasks:
    - name: Installing {{ packages }} on {{ hostname }}
      yum:
        name: "{{ item }}"
        state: present
      with_items: "{{ packages }}"

Ansible 变量简介

此 playbook 使用了已定义(例如 packages)和未定义(例如 hostname)的变量。Ansible 可以通过几种方式初始化任意变量(即,Ansible 收集事实时未定义的变量)

  1. 使用 playbook 的 vars: 部分,如 上一篇文章 中的示例 4 所示。在此级别定义的变量位于 本地作用域 中,这意味着它们仅对直接 playbook 可访问,而对后续 playbook 不可访问。
  2. 定义 vars 文件,如果您正在处理的 Ansible 项目具有定义的正确文件夹结构,则可能会发生这种情况。(在此不再深入探讨,但您可以阅读 关于角色的官方文档 以获取更多信息。)
  3. 使用 --extra-vars= 参数运行 playbook。

示例 1 中的 playbook 旨在与 --extra-vars= 参数一起运行。要运行 playbook,完整命令如下所示

ansible-playbook install_git.yaml --extra-vars="hostname=git"

这种传递变量的方法是最灵活的,并且对于特定类型的 playbook 来说,可能是最理想的。

变量可以用不仅仅是字符串来定义;Ansible 还支持 数据结构。数据结构是指可以存储和访问数据的方式。Ansible 中最常用的类型是 列表字典

列表用方括号内的一系列变量表示。在示例 1 中,["git", "nmap"] 在名为 packages 的列表中定义。字典用花括号 ({}) 定义,并使用键值对表示法,如下所示:{ username: jdoe, group: users } 我不会在本系列中深入探讨何时使用每种类型的数据结构,但重要的是要意识到 Ansible 支持不止一种类型。

注意:示例 1 中包含 NMAP 实用程序只是为了演示 Ansible 中列表的定义。

这个小型 playbook 中引入的最后一个新概念是 with_items: 行。这是 Ansible 中一个有用的功能。它类似于 for 循环 的概念。Ansible 将迭代列表中的每个项目并根据其采取行动;但是,与其他编程语言不同,您可能无法定义循环中使用的变量的名称。在 Ansible 中,循环变量始终是单词 item

最后需要注意的是,您可能已经注意到可以在任务名称中使用一些变量。这有助于在 Ansible 运行期间提供描述性输出。例如,以下是示例 1 中 playbook 的任务输出

TASK [Installing [u'git', u'nmap']] on git
*************************************************************
changed: [git] => (item=[u'git', u'nmap'])

尽管列表只是在任务名称中转换为文本,但运行 playbook 的人可以知道哪些软件包正在安装到哪个主机。

使用 Ansible 创建用户

下一步是创建 git 用户。以下 playbook 将执行此操作

示例 2:创建 Git 用户

- hosts: "{{ hostname }}"
  gather_facts: false
  tasks:
    - name: create and/or change {{ username}}'s  password
      user:
        name: "{{ username }}"
        password: MYg1tpassw0rd

此 playbook 也依赖于运行时使用的 --extra-vars= 参数。与之前类似,playbook 的运行方式如下

ansible-playbook user_setup_with_params.yaml --extra-vars="hostname=git username=git"

此 playbook 引入了 user 模块,如果需要,可以传入更多选项。此模块的功能正如您所期望的那样,因此没有太多可讨论的内容。与 Unix 等效命令类似,user 模块可用于在系统上创建、管理或删除本地用户。一般来说,如果您的用户是集中管理的(例如在 Active Directory 或 LDAP 中),则不应使用此模块。

启用示例 Git 仓库

还剩下两个步骤才能完全启动并运行 Git SSH 服务器

  1. 创建一个示例裸仓库,供用户协作。
  2. 启用对 Git 用户的 SSH 访问,以便人们可以提交和拉取 playbook。

要创建 Git 仓库,示例 3 中的 playbook 演示了 command 模块(它只是像您在终端中键入的那样运行 shell 命令)以及 file 模块。尽管 Ansible 通常为大多数任务提供本机模块(例如 Git 模块),但在某些情况下,该模块可能无法完全满足您的需求。在这些情况下,使用 command 模块是可以接受的。

警告:command 模块是幂等的!这意味着 command 模块将运行,无论任务是否先前已完成。在某些情况下,例如处理 SSL 证书,多次发出相同的命令可能会产生意外的副作用。

示例 3:创建初始 Git 仓库

- hosts: "{{ hostname }}"
  gather_facts: False
  tasks:
    - name: git init --bare {{ project }} with the command module
      command: git init --bare {{project}}
      args:
        chdir: "{{ git_base_dir }}"
      become_user: git
    
    - name: Set the permissions on {{ git_base_dir }}/{{ project }}
      file:
        path: "{{ git_base_dir }}/{{ project }}"
        state: directory
        mode: 0755
        owner: git
        group: git 
        recurse: True

请注意第一个任务的 args:chdir: 部分。这些是提供给 command 模块的可选指令。正如人们可能期望的那样,chdir: 在命令运行之前将当前工作目录更改为指定的位置。这确保了 Git 仓库在所需位置创建。

在示例 3 中,我也可以使用 command 模块来设置目录的权限。(使用 command 模块时的默认权限是从当前的 Ansible 用户继承的。在这种情况下,仓库的所有者将是 root:root 而不是 Git 用户。)但是,我试图演示几个不同的模块,并尽可能保持幂等性。我正在使用的 file 模块应该是自我解释的。要运行示例 3 中的 playbook,请使用以下命令

ansible-playbook initialize_git.yaml --extra-vars="hostname=git git_base_dir=/home/git/ project=newgitproject"

Git 基础知识

要使用新安装的 Git 服务器,每个需要提交代码的用户都必须将其 SSH 密钥安装到远程主机上 git 用户的 authorized_keys 文件中。

可以使用多种方法来管理 SSH 密钥的传播。

示例 4:使用 authorized_key 模块和文件 glob 传播 SSH 密钥

- hosts: "{{ hostname }}"
  gather_facts: false
  tasks:
    - name: copy ssh key using FILEGLOB
      authorized_key:
        key: "{{ lookup('file', item) }}"
        user: "{{ username }}"
        state: present
        exclusive: False
      with_fileglob: ../files/*.pub

在示例 4 中,fileglob 模块允许传播目录中的所有 SSH 密钥。在本例中,示例 4 中的 playbook 将推送任何以 .pub 结尾的 SSH 密钥。当您有很多 SSH 密钥要推送并且不想全部列出时,这很有用。

示例 5:使用 authorized_key 模块和 with_items 传播 SSH 密钥

- hosts: "{{ hostname }}"
  gather_facts: false
  vars:
    ssh_keyfile: [ "user1_ssh_key.pub", "user2_ssh_key.pub" ]
  tasks:  
    - name: copy ssh key using ITEM NAME
      authorized_key:
        key: "{{ lookup('file', '../files/'+item) }}"
        user: "{{ username }}"
        state: present
        exclusive: False
      with_items: 
        - "{{ ssh_keyfile }}"

在示例 5 中,每个密钥都通过列表 ssh_keyfile 按名称指定。它使用 with_items 循环遍历 ssh_keyfile 列表中的每个密钥。这种方法的优点是每个密钥都必须经过深思熟虑地添加,而不是推送目录中的每个密钥文件。由于 key: 属性在 authorized_key 模块内部的形成方式,此方法要求所有密钥都位于同一目录中。

图 6:使用 authorized_key 模块和 with_file 传播 SSH 密钥

- hosts: "{{ hostname }}"
  gather_facts: false
  tasks:
    - name: using with_file
      authorized_key:
        key: "{{ item }}"
        user: "{{ username }}"
        state: present
        exclusive: False
      with_file: 
        - ../files/user1_ssh_key.pub
        - ../files/user2_ssh_key.pub

示例 6 介绍了 with_file 的概念。它与示例 5 类似,只是它不要求密钥位于同一目录中。从技术角度来看,这些方法都没有本质上优于其他方法。每种方法都具有安全性和维护方面的含义,应根据具体情况进行考虑。对于家庭设置中的小型安装,所有这些方法都是完全可以接受的。要运行上述任何 playbook,请使用以下命令

ansible-playbook install_ssh_keys.yaml --extra-vars="hostname=git username=git"

现在 SSH 密钥已安装在 Git SSH 服务器上,您的用户可以检出代码并开始为新项目做贡献。要从 Git SSH 服务器拉取 newgitproject 项目,请发出以下命令(作为 SSH 密钥已使用示例 4、5 或 6 中的方法之一安装的用户)。

[user@host ~]$ git clone ssh://git@git/home/git/newgitproject

您将收到以下输出

Cloning into 'newgitproject'...
warning: You appear to have cloned an empty repository.

我将创建一个空文件来演示该过程

cd newgitproject
touch test.txt

接下来,将文件添加到 Git 以进行跟踪

git add test.txt
git commit -m "first commit of test.txt

您将看到如下所示的输出

Committer: somecomment <user@host>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly. Run the
following command and follow the instructions in your editor to edit
your configuration file:

    git config --global --edit

执行此操作后,您可以使用以下命令修复用于此提交的身份

git commit --amend --reset-author
1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 test.txt

有关配置 Git 客户端的信息,请参阅 首次设置的官方文档。但是,即使不使用 Git 配置选项,您仍然可以推送到 Git SSH 服务器。如果您使用 git log,您应该会看到类似于以下内容的内容

commit f9bd46c57211fa5c35831bbe0ce1f9c0a34a0eba
Author: somecomment <user@host>
Date:   Wed Jul 12 08:41:20 2017 -0400

    first commit of test.txt

至此,您应该拥有一个功能正常的 Git SSH 服务器。作为最佳实践,每次对 playbook 进行更改时,都应将其检入 Git 服务器。这既提供了跟踪更改的能力,又为您提供了在出现问题时轻松回滚的点。

下一步

我已经介绍了从 Ansible 管理系统所需的一些技能。在下一篇文章中,我将开始使用 Prometheus 进行数据收集,并使用 Grafana 进行数据可视化来设置监控。我将使用各种 Ansible 模块来完成这些任务,这些模块应该为您提供一个坚实的基础,您可以从中创建自己的 playbook。

User profile image.
Steve 是一位敬业的 IT 专业人士和 Linux 倡导者。在加入红帽之前,他曾在金融、汽车和电影行业工作多年。Steve 目前在红帽解决方案和技术实践部门担任架构师。他拥有从 RHCA(DevOps 方面)到 Ansible,再到容器化应用程序等方面的认证。

评论已关闭。

Creative Commons License本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 获得许可。
© . All rights reserved.