準(zhǔn)備好安裝了Ansible的主機(jī),作為實(shí)驗(yàn)環(huán)境。
有一臺新安裝的Centos7系統(tǒng),利用ansible在主機(jī)上完成以下操作:
準(zhǔn)備好一臺安裝了Centos7系統(tǒng)的主機(jī),然后去ansible的主機(jī)上對目標(biāo)主機(jī)進(jìn)行操作。
我這里的ansible也是新安裝的,所以如果遇到一些沒有的工具,也會在遇到的時(shí)候一步一步進(jìn)行添加。下面是匯總的內(nèi)容。
對于一臺新裝好的ansible,還是會缺少很多依賴項(xiàng),有些和特定模塊關(guān)聯(lián)的比較緊密,可以在使用特定模塊的時(shí)候再安裝。
還有一些使用范圍比較廣,建議先裝好:
修改ansible.cfg配置文件
我的實(shí)驗(yàn)環(huán)境,為了測試方便,暫時(shí)只有下面3項(xiàng)做了設(shè)置:
[defaults]
#host_key_checking = False
inventory = ~/hosts
vault_password_file = ~/vault_password_file
配置文件第一行的[defaults]不能省。
編輯 /etc/ansible/hosts 添加主機(jī)信息:
host1 ansible_host=192.168.24.172
我的實(shí)驗(yàn)環(huán)境是直接放到了家目錄里了
先用ping模塊測試一下連通性:
[root@Ansible ~]# ansible host1 -m ping -k
SSH password:
host1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
[root@Ansible ~]#
這里使用了-k參數(shù),手動輸入密碼。
測試聯(lián)通性,可以再加上-c參數(shù),指定local。不過這里要驗(yàn)證一下ssh連接。
安裝 sshpass
如果是第一次使用,可能會提示需要安裝sshpass。這個(gè)簡單,yum安裝即可:
$ yum install sshpass
添加密碼信息
最好的做法是用SSHKey實(shí)現(xiàn)免密碼登錄。這里講使用密碼的情況。
為了方便,也可以把密碼加到配置中,這樣不用每次都輸入密碼:
host2 ansible_host=192.168.24.172 ansible_ssh_pass=123456
這樣做,密碼就是明碼存放了,很不安全。下面有更安全的做法。
使用 ansible-vault 來加密敏感信息
修改配置文件
這步不是必須的,運(yùn)行命令的時(shí)候可以加上參數(shù) --vault_password_file 來指定你的密碼文件。不過通過設(shè)置就可以把這個(gè)參數(shù)省了:
$ vi /etc/ansible/ansible.cfg
# If set, configures the path to the Vault password file as an alternative to
# specifying --vault-password-file on the command line.
vault_password_file = ~/vault_password_file
使用openssl來生成隨機(jī)密碼
使用 openssl 來生成隨機(jī)的base64編碼的內(nèi)容:
$ openssl rand -base64 128 -out vault_password_file
$ chmod a-w vault_password_file
$ chattr +i vault_password_file
文件生成后,對文件做了一些保護(hù),防止文件被修改。修改文件的ugo權(quán)限只對普通用戶有效,root依然可以修改文件。后面的命令可以鎖定文件,即使root也無法修改了,防止對文件的意外操作。
如果需要修改或者刪除文件,可以先把文件解鎖,只要把命令的 +i 改成 -i 就可以了:
$ chattr -i vault_password_file
生成加密后的字符串
下面是使用 ansible-vault 來生成加密后的字符串:
[root@Ansible ~]# ansible-vault encrypt_string "123456" --name ansible_ssh_pass
ansible_ssh_pass: !vault |
$ANSIBLE_VAULT;1.1;AES256
33336539373437373161326537323836343163633532396235383334326562303134626565613537
3134313631393931376361363761313165393966613831360a343338353765326331663433613533
31636238613133363639336130613264386366363931663230333663363062333836323730383563
6562626265393535310a623732633863633765363066636265303265316661373464323961666131
6561
Encryption successful
[root@Ansible ~]#
接下來需要把這里獲得的信息復(fù)制到配置文件中。
修改主機(jī)配置文件
這里對配置文件進(jìn)行了大修改,原來是INI格式的,現(xiàn)在改成了YAML格式:
---
all:
hosts:
host1:
ansible_host: 192.168.24.172
ansible_ssh_pass: !vault |
$ANSIBLE_VAULT;1.1;AES256
33336539373437373161326537323836343163633532396235383334326562303134626565613537
3134313631393931376361363761313165393966613831360a343338353765326331663433613533
31636238613133363639336130613264386366363931663230333663363062333836323730383563
6562626265393535310a623732633863633765363066636265303265316661373464323961666131
6561
...
要使用YAML是因?yàn)镮NI格式不支持內(nèi)嵌vault,官方的說明如下:
This is an example using an extract from a YAML inventory, as the INI format does not support inline vaults:
INI格式的主機(jī)配置文件,可讀性感覺更好。如果依然希望使用INI格式的配置,可以另外再創(chuàng)建vars文件,把額外的參數(shù)以YAML格式寫在另一個(gè)文件中。
驗(yàn)證
這次用command模塊了進(jìn)行驗(yàn)證:
$ ansible host1 -a hostname
host1 | CHANGED | rc=0 >>
Host1
$
至此準(zhǔn)備工作都做完了,已經(jīng)能成功連接到主機(jī)。
python多個(gè)版本并存是很常見的情況。Centos7系統(tǒng)安裝后默認(rèn)就有一個(gè)python2,一般自己要使用python3就會再安裝一個(gè),這個(gè)就會帶來一些問題。
之前遇到的問題,就是ansible使用了目標(biāo)主機(jī)的python3來執(zhí)行任務(wù),而有模塊使用python3會有問題。
之前有問題的主機(jī)是將系統(tǒng)的python命令指向了python3。并且去yum相關(guān)的命令中修改了開頭的#!/usr/bin/python2
來保證yum可以正常運(yùn)行。
而ansible默認(rèn)就會去目標(biāo)主機(jī)查找 /usr/bin/python
來執(zhí)行,這就造成了默認(rèn)使用python3來執(zhí)行的情況。
這里就強(qiáng)行將ansible_python_interpreter的值指向目標(biāo)主機(jī)的python3來將問題再現(xiàn)出來。
yum 是用python2寫的,所以不支持python3。下面是報(bào)錯(cuò)的情況:
[root@Ansible ~]# ansible host1 -m yum -a "name=wget state=present" -e "ansible_python_interpreter=/usr/bin/python3"
host1 | FAILED! => {
"ansible_facts": {
"pkg_mgr": "yum"
},
"changed": false,
"msg": "The Python 2 bindings for rpm are needed for this module. If you require Python 3 support use the `dnf` Ansible module instead.. The Python 2 yum module is needed for this module. If you require Python 3 support use the `dnf` Ansible module instead."
}
[root@Ansible ~]#
根據(jù)msg的提示。建議使用dnf,但是嘗試之后還是失敗了。
簡單的辦法就是指定 ansible_python_interpreter 參數(shù),使用Python2。
使用yum模塊必須指定python2,暫時(shí)沒別的辦法。
在使用 get_utl 模塊的時(shí)候,就會遇到selinux的問題。這類問題應(yīng)該只要把selinux關(guān)掉應(yīng)該就解決了(沒試過),不過這里看看不關(guān)的情況。
[root@Ansible ~]# ansible host1 -m get_url -a 'url="http://mirrors.aliyun.com/repo/epel-7.repo" dest="/etc/yum.repos.d/epel-7.repo"' -e "ansible_python_interpreter=/usr/bin/python3"
host1 | FAILED! => {
"changed": false,
"msg": "Aborting, target uses selinux but python bindings (libselinux-python) aren't installed!"
}
[root@Ansible ~]#
一個(gè)辦法還是使用python2,因?yàn)橄到y(tǒng)默認(rèn)已經(jīng)安裝好了python2版本的selnux,應(yīng)該就是下面這個(gè):
[root@PlayHost ~]# yum info libselinux-python
已加載插件:fastestmirror
Loading mirror speeds from cached hostfile
* base: ftp.sjtu.edu.cn
* extras: ftp.sjtu.edu.cn
* updates: ftp.sjtu.edu.cn
已安裝的軟件包
名稱 :libselinux-python
架構(gòu) :x86_64
版本 :2.5
發(fā)布 :14.1.el7
大小 :589 k
源 :installed
來自源:anaconda
簡介 : SELinux python bindings for libselinux
網(wǎng)址 :https://github.com/SELinuxProject/selinux/wiki
協(xié)議 : Public Domain
描述 : The libselinux-python package contains the python bindings for developing
: SELinux applications.
[root@PlayHost ~]#
如果使用python2也就沒這個(gè)問題了。
使用python3也是可以的,只要把這個(gè)包裝上。在yum里沒有找到對應(yīng)的python3版本,不過pip里有:
[root@PlayHost ~]# pip install selinux
Collecting selinux
Downloading https://files.pythonhosted.org/packages/59/38/780baac7aafcf44cca8e77318ec935660f93fc30e3de92f8de7a7dbc0513/selinux-0.1.6-py2.py3-none-any.whl
Installing collected packages: selinux
Successfully installed selinux-0.1.6
[root@PlayHost ~]#
這里的操作是在目標(biāo)主機(jī)上進(jìn)行的,也可以用ansible遠(yuǎn)程來操作。不過這里主要是為了講明白問題。
建議在目標(biāo)主機(jī)上安裝python3之后,就順便把selinux也裝上。這樣有些python2和python3都兼容的模塊使用任何版本都不會有問題
初始的系統(tǒng)是沒有pip的,之后我也只會為python3安裝pip。并且所有需要pip安裝的python模塊都是為python3安裝的。
所以在安裝pip的時(shí)候,需要指定 ansible_python_interpreter 參數(shù),使用Python3。這個(gè)和yum模塊正好相反。
使用pip模塊的時(shí)候,可以加參數(shù) extra_args: -i https://mirrors.aliyun.com/pypi/simple/
來指定pypi源。
不過為方便起見,也可以直接寫在配置文件中指定默認(rèn)的pypi源。配置文件也用命令可以添加,不用編輯文件。使用的命令如下:
$ pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
運(yùn)行命令可以用command模塊來實(shí)現(xiàn)。
安裝pip和更新
安裝我是用yum模塊來安裝python36-pip(使用easy_install模塊安裝會有問題,我解決不了)。安裝完成后,再用pip模塊更新pip。
更新了pip之后,再順便把selinux也裝上,就是上一小節(jié)的問題。
這里要用自己測試環(huán)境的ansible去配置一臺主機(jī)。完成初始配置后,要安裝好python3和docker,然后再創(chuàng)建一個(gè)ansible的鏡像。最后還有SSH和賬戶的安全設(shè)置。
主要是設(shè)置國內(nèi)的鏡像源,然后使用yum來安裝工具:
---
- hosts: host1
vars:
ansible_python_interpreter: /usr/bin/python2 # 指定使用python2,防止有坑
tasks:
- name: 刪除默認(rèn)的repo文件
file:
path: "/etc/yum.repos.d/{{ item }}"
state: absent
with_items:
- CentOS-Base.repo
- CentOS-Debuginfo.repo
- CentOS-Media.repo
- CentOS-Vault.repo
- CentOS-CR.repo
- CentOS-fasttrack.repo
- CentOS-Sources.repo
- name: 下載阿里源的 Centos-7.repo epel-7.repo
get_url:
url: "http://mirrors.aliyun.com/repo/{{ item.url }}"
dest: "/etc/yum.repos.d/{{ item.dest }}"
with_items:
- {url: "Centos-7.repo", dest: "CentOS-7.repo"}
- {url: "epel-7.repo", dest: "epel-7.repo"}
- name: yum安裝 wget net-tools bind-utils net-snmp-utils traceroute lrzsz
yum:
name:
- wget
- net-tools
- bind-utils
- net-snmp-utils
- traceroute
- lrzsz
state: present
...
使用yum來安裝python3和pip,然后再更新pip到最新版本,并設(shè)置國內(nèi)的pip鏡像源:
---
- hosts: host1
tasks:
- name: yum 安裝 python3
yum:
name: [python36, python36-setuptools, python36-pip]
state: present
- name: 更新 pip
# 有 easy_install 安裝會報(bào)錯(cuò),這里用 pip 更新
pip:
name: pip
state: latest
extra_args: -i https://mirrors.aliyun.com/pypi/simple/
# 用python3的pip要指定python3,否則有可能去調(diào)用python2的pip
vars: {ansible_python_interpreter: /usr/bin/python3}
- name: 檢查pip配置文件是否存在
file:
path: ~/.config/pip/pip.conf
state: file
ignore_errors: True
register: result
- name: 如果pip配置文件不存在:設(shè)置使用阿里源
command: pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
when: result is failed
- name: 安裝 selinux
pip: {name: selinux, state: present}
vars: {ansible_python_interpreter: /usr/bin/python3}
...
按之前說的,順便把selinux也安裝上。
安裝docker沒有太大問題,需要先把docker-py安裝上。用pip安裝,所以docker模塊只能在python3環(huán)境上運(yùn)行、
之前已經(jīng)把selinux也裝上。這樣除了yum,其他都可以在python3環(huán)境上運(yùn)行了。
---
- hosts: host1
vars:
ansible_tag: v1 # 指定ansible鏡像的tag(版本號)
tasks:
- name: 下載阿里的安裝源
get_url:
url: http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
dest: /etc/yum.repos.d/
- name: yum 安裝 docker-ce 指定版本
yum:
name: docker-ce-18.06.0.ce-3.el7
state: present
- name: 啟動docker,開機(jī)啟動
service: name=docker.service state=started enabled=yes
- name: 檢查docker配置文件是否存在
file:
path: /etc/docker/daemon.json
state: file
ignore_errors: True
register: result
- name: 如果docker配置文件不存在,則創(chuàng)建初始文件設(shè)置鏡像加速器
when: result is failed
block:
- name: 文件寫入內(nèi)容,設(shè)置設(shè)置鏡像加速器
lineinfile:
path: /etc/docker/daemon.json
create: yes
line: |
{
"registry-mirrors": ["http://hub-mirror.c.163.com", "https://docker.mirrors.ustc.edu.cn"]
}
- name: 重啟docker,使鏡像加速器生效
service: name=docker.service state=restarted
- name: 安裝管理docker的模塊,檢查鏡像是否存在
vars: {ansible_python_interpreter: /usr/bin/python3}
block:
- name: pip 安裝 docker-py selinux
pip:
name: [docker-py, selinux]
state: present
- name: 檢查 Ansible 鏡像是否存在
vars: {ansible_python_interpreter: /usr/bin/python3}
docker_image:
name: ansible
tag: "{{ ansible_tag }}"
source: local
ignore_errors: True
register: result
- name: 制作 Ansible 鏡像
vars: {ansible_python_interpreter: /usr/bin/python3}
when: result is failed
block:
- name: 將 Dockerfile copy 到目標(biāo)主機(jī)
# copy 需要 selinux,所以上面用 pip 安裝了 python3 的版本
copy:
src: ansible/Dockerfile
dest: /tmp/docker_file/ansible/
- name: docker build
docker_image:
name: ansible
tag: "{{ ansible_tag }}"
build:
path: /tmp/docker_file/ansible/
pull: yes
source: build
- name: 刪除 Dockerfile
file:
path: /tmp/docker_file/
state: absent
...
docker的配置文件是json格式的,json沒有注釋,所以不能用blockinfile模塊??梢杂胠ineinfile模塊,也可以用copy模塊。不過copy模塊有個(gè)小問題,沒法遞歸創(chuàng)建目錄。而lineinfile模塊有create參數(shù),并且也支持多行。
這個(gè)是構(gòu)架ansible的Dockerfile:
FROM centos:centos7
RUN curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo && \
yum -y install python36 python36-setuptools python36-pip && \
yum clean all && \
pip3 install pip --upgrade -i https://mirrors.aliyun.com/pypi/simple/ && \
/usr/local/bin/pip3 install ansible -i https://mirrors.aliyun.com/pypi/simple/ && \
mkdir /opt/ansible_project/etc/ansible -p && \
ln -s /opt/ansible_project/etc/ansible/ /etc/ansible
VOLUME /opt/ansible_project
CMD ["ansible", "--version"]
創(chuàng)建鏡像查找的Dockerfile所在的文件夾是在目標(biāo)主機(jī)上的。所以需要先用copy模塊將文件夾復(fù)制過去。
copy模塊使用相對目錄時(shí),源文件的起始目錄是playbook所在的目錄,目標(biāo)的起始目錄有目標(biāo)主機(jī)決定(Centos的系統(tǒng),默認(rèn)登錄后就在用戶的家目錄)。
中文亂碼
測試后發(fā)現(xiàn)這個(gè)基礎(chǔ)鏡像是不支持中文字符的。需要在Dockerfile中在添加如下的內(nèi)容:
RUN yum install kde-l10n-Chinese -y
RUN yum install glibc-common -y
RUN localedef -c -f UTF-8 -i zh_CN zh_CN.utf8
RUN export LANG=zh_CN.UTF-8
RUN echo "export LANG=zh_CN.UTF-8" >> /etc/locale.conf
ENV LANG zh_CN.UTF-8
ENV LC_ALL zh_CN.UTF-8
只在做好的鏡像上解決了中文字符的問題。上面的內(nèi)容沒有測試,所以先單獨(dú)列出來,沒有合并到整個(gè)Dockerfile中。
主要做了2件事:
playbook如下:
---
- hosts: host1
vars:
ansible_python_interpreter: /usr/bin/python2 # 指定使用python2,防止有坑
init_ssh_user: admin # 是否創(chuàng)建用戶,并且會禁用root密碼登錄
init_ssh_port: 2849 # 是否修改默認(rèn)ssh端口
tasks:
# 創(chuàng)建管理員用戶,禁用root登錄
- block:
- name: 創(chuàng)建用戶 {{ init_ssh_user }}
user:
name: "{{ init_ssh_user }}"
# 這個(gè)是加鹽的對稱加密,所以可以反解,官網(wǎng)有生成密碼的方式:
# https://docs.ansible.com/ansible/latest/reference_appendices/faq.html#how-do-i-generate-encrypted-passwords-for-the-user-module
password: "$6${{ my_secret_salt }}$CSQSsXSoAkwtWDzjlReQ3u0jy1YyxBLouwe403dCVe.ystdi9JQvjSxhoTpYwNoT5nprsJV/UpYb9Ktj.7jLX/"
groups: wheel
state: present
- name: 修改 /etc/ssh/sshd_config 禁止root登錄
lineinfile:
dest: /etc/ssh/sshd_config
state: present
regexp: "^#?PermitRootLogin"
line: "PermitRootLogin no"
notify: systemctl restart sshd.service
when: init_ssh_user is defined
# 修改ssh端口
- block:
- name: 防火墻開啟端口 {{ init_ssh_port }}
firewalld:
port: "{{ init_ssh_port }}/tcp"
state: enabled
permanent: yes
immediate: yes
- name: yum安裝 policycoreutils-python
yum: { name: policycoreutils-python, state: present}
- name: 設(shè)置selinux:`semanage port -a -t ssh_port_t -p tcp {{ init_ssh_port }}`
seport:
ports: "{{ init_ssh_port }}"
proto: tcp
setype: ssh_port_t
state : present
- name: 修改 /etc/ssh/sshd_config 的端口設(shè)置
lineinfile:
dest: /etc/ssh/sshd_config
state: present
regexp: "^#?Port"
line: "Port {{ init_ssh_port }}"
notify: systemctl restart sshd.service
when: init_ssh_port is defined
handlers:
- name: systemctl restart sshd.service
service: name=sshd.service state=restarted
...
去目標(biāo)主機(jī)上驗(yàn)證:
# docker run --rm ansible:v1
ansible 2.8.4
config file = None
configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/local/lib/python3.6/site-packages/ansible
executable location = /usr/local/bin/ansible
python version = 3.6.8 (default, Apr 25 2019, 21:02:35) [GCc 4.8.5 20150623 (Red Hat 4.8.5-36)]
#
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)cdcxhl.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。