山姆鍋最近需要安裝 Jenkins 這個持續整合軟體,但不打算採用過去手動的安裝模式,而是嘗試運用 Vagrant, Puppet 跟 Virtualbox 來做自動部署。持續整合軟體一般建議不要在 Master 上執行建構工作, 所以,本次的實驗就以安裝一台 Master 與一台 Slave 主機為目標。

由於之後應該陸續會有類似的實驗,山姆鍋將相關的程式碼放在 devops-labs 這個 GitHub 項目以方便讀者參考。 本文主要 Puppet 的 manifests 腳本放在 recipies/jenkins-ci 這個目錄中。為了完整性,山姆鍋也將相關需要的 Puppet modules 放在這個項目中, 這樣讀者只要 git clone 之後,便可以簡單以下列指令看實際執行的結果:

1
2
3
$ git submodule update --init
$ cd recipes/jenkins-ci
$ vagrant up

如果執行順利,使用瀏覽器連到 http://192.168.33.10:8080/computer,應該可以看到下列畫面:

Jenkins dashboardJenkins dashboard

請注意:本文的設置,Jenkins 並沒有開啓任何安全設定,也就是說,沒有加上必要安全認證之前, 不要在網路上使用!

準備工作

您的測試機上需已經安裝有下列軟體:

  1. Git
  2. Vagrant 1.1+
  3. VirtualBox 4.1 or 4.2

注意:Vagrant 目前不支援 VirtualBox 4.3。

本文的方法需要依賴下列 Puppet 模組:

puppet-java 這個模組,跟在 「使用 Puppet 在 Ubuntu 系統上自動安裝 Oracle JDK」 說明的差不多,不過改成使用 puppet-apt 來做系統套件庫管理。

虛擬機設定

目標是要安裝兩台服務器,一台當作 Jenkins master,一台當作 Jenkins slave。 Jenkins slave 會自動加入 Jenkins master 的叢集中,如此,master 就可以開始分配工作給 slave 執行。 理想上,可以按照需要依照同樣的設定增加 Jenkins slave。

下面是有關服務器的 Vagrant 設定檔:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# -*- mode: ruby -*-
# vi: set ft=ruby :

# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

config.vm.box_url = "http://files.vagrantup.com/precise64.box"

config.vm.define :master, primary: true do |master|
master.vm.box = "precise64"
#master.vm.forward_port 8080, 8080
master.vm.network :private_network, ip: "192.168.33.10"
master.vm.hostname = "ci-master.example.com"

master.vm.provider :virtualbox do |vb|
# Use VBoxManage to customize the VM. For example to change memory:
vb.customize ["modifyvm", :id, "--memory", "512"]
end

master.vm.provision :puppet, :module_path => "../../modules" do |puppet|
puppet.manifests_path = "manifests"
puppet.manifest_file = "master.pp"
puppet.facter = { 'fqdn' => master.vm.hostname }
end
end

config.vm.define :slave do |slave|
slave.vm.box = "precise64"

slave.vm.network :private_network, ip: "192.168.33.11"
slave.vm.hostname = "ci-slave.example.com"

slave.vm.provider :virtualbox do |vb|
# Use VBoxManage to customize the VM. For example to change memory:
vb.customize ["modifyvm", :id, "--memory", "512"]
end

slave.vm.provision :puppet, :module_path => "../../modules" do |puppet|
puppet.manifests_path = "manifests"
puppet.manifest_file = "slave.pp"
puppet.facter = { 'fqdn' => slave.vm.hostname }
end
end
end

由於 Vagrant box 內建的 Puppet 無法正確取得’fqdn’(主機域名), 需要加入 puppet.facter = { ‘fqdn’ => master.vm.hostname } 與 puppet.facter = { ‘fqdn’ => slave.vm.hostname } 來讓 Puppet 可以直接使用而不嘗試採用 facter 取得。

網路的部分,使用 private network,也就是 hostonly 模式。這樣虛擬機之間,主機與虛擬機就可以互相溝通。

Master 的 Puppet 組態檔

下列是 Jenkins master 的組態檔內容:

1
2
3
4
5
6
7
8
9
10
11
class { 'apt':
}

class { 'java':
}

class {'jenkins':
install_java => false,
}

include jenkins::master

因為,Jenkins 這個 Puppet 模組預設會試圖安裝 Java 環境,所以, 'install_java’設為 false 就是讓它跳過安裝 Java 的步驟。

Slave 的 Puppet 組態檔

跟 Jenkins master 的主要差別在於'class {‘jenkins::slave’ 這個部分,其中也指定 Jenkins master 的為止,讓 Jenkins slave 可以自行向 master 註冊。'ui_user’跟’ui_pass’目前是沒有作用的。

1
2
3
4
5
6
7
8
9
10
11
12
class { 'apt':
}

class { 'java':
}

class { 'jenkins::slave':
masterurl => 'http://192.168.33.10:8080',
ui_user => 'adminuser',
ui_pass => 'adminpass',
install_java => false,
}

結語

希望這個配方 (recipe) 對您有些幫助,但就像醫師的配方一樣,不同人的配方或多或少不同, 可不能隨便服用。同樣地,本文提供的配方,主要目的是了解如何以 Vagrant, Puppet 來進行自動部署, 使用 Jenkins 只是希望有個比較實際的例子。