|
|
楼主 |
发表于 2021-8-2 10:51:52
|
显示全部楼层
1 Ansible管理docker
# h8 L# s1 n4 e4 A, J近年来Linux容器技术越来越受欢迎,通过容器技术,可以保持程序运行环境的一致性,快速启动并高效率运行,涉及到的开销也比较小,此外,在系统层次上完成容器级别的资源隔离非常快速。
1 ]* k& U: u5 t( DDocker是管理Linux容器最流行的工具,它为管理Linux容器提供了许多方便的工具,比如创建、销毁Linux容器,还提供了一些除管理Linux容器之外的工具,比如管理镜像、编排。通过它的易用性,Docker已经成为管理容器的最流行的方法之一。
) e$ q- t1 \+ {" m% G题外话:关于容器和Docker- d$ U3 `) }1 c# j
Linux容器是内核的几种功能组合在一起实现的。换句话说,Linux容器技术是内核层次的功能,Docker只是提供了一系列工具,包括从底层和内核交互到高层和用户交互的一条龙。除了Docker外,也还有其它操作Linux容器的工具,只是对大众来说,Docker是最流行的。, s4 T! q- A! f% `+ A6 }
Ansible为Docker提供了一整套工具,包括相关模块、连接插件(ansible_connection: docker)和inventory脚本,因此Ansible可在许多方面与Docker进行交互。例如Ansible可构建Docker镜像、启动或停止容器、组合多个容器服务、连接到活动容器并与之交互,甚至可以从容器中获取inventory。9 W+ ]0 F: m* U* K
如下是Ansible官方目前提供的和Docker相关的模块:' M7 D% D/ y5 D* ~4 O/ l# d
Code
3 F3 H& z( v$ |6 h
. J- T+ h* A9 W9 e0 y: Xdocker_compose – Manage multi-container Docker applications with Docker Compose
5 A! v) f" C* S ]docker_config – Manage docker configs/ G4 v# q" U, m4 S: k# _
docker_container – manage docker containers2 b- {7 }) j' i5 K J1 N5 {4 G$ \6 [
docker_container_info – Retrieves facts about docker container
; x! D- y4 ~' o3 v3 Wdocker_host_info – Retrieves facts about docker host and lists of objects of the services; y% F! Y: o( _4 \6 v( g
docker_image – Manage docker images
; @/ y7 D- \% Ydocker_image_info – Inspect docker images% |3 a8 p& @% r% U0 I+ O7 C6 U
docker_login – Log into a Docker registry$ l. P0 `8 V9 y5 [) S6 ^7 i% P) |
docker_network – Manage Docker networks! x# I9 U+ E7 z5 \
docker_network_info – Retrieves facts about docker network2 {) x. i9 P3 Z, E+ |. M) l9 ]
docker_node – Manage Docker Swarm node
4 w" @2 Z6 Y/ E- Z2 T6 A+ v3 adocker_node_info – Retrieves facts about docker swarm node from Swarm Manager; K8 J0 U$ W; I0 ]$ i9 D- P
docker_prune – Allows to prune various docker objects
0 m9 r ]0 g0 p; v( a Q& g* Kdocker_secret – Manage docker secrets8 t6 \5 P, N5 n- a/ p' z
docker_stack – docker stack module3 Q' K1 C9 K' b! L" j
docker_swarm – Manage Swarm cluster$ |/ e% S: ?9 O+ B
docker_swarm_info – Retrieves facts about Docker Swarm cluster
; r2 t3 l/ `* ^docker_swarm_service – docker swarm service
' p) I6 K' ^, Pdocker_swarm_service_info – Retrieves information about docker services from a Swarm Manager
1 w7 _ k$ I+ i" T. Y( kdocker_volume – Manage Docker volumes
. [/ }& V8 O8 Z0 U" X) f7 B7 Odocker_volume_info – Retrieve facts about Docker volumes
, b3 }! o. Y$ Z要使用Ansible管理连接Docker,要求安装如下包(注意:Ansible端和docker端都安装,这一点和其它模块不一样,如报错,请自行在两端安装、卸载、升级调试):
& D0 o( _! W @: d* M& ]Shell
9 s/ x5 w A _& {7 K& k/ ]6 k! a" e# E0 F$ _! Q7 l' F
# 两端都安装,如果已经安装了,则在报错的情况下按需更新) ] T- I$ D7 U. l
# 此外,根据Ansible使用的python解释器版本,按需决定使用pip还是pip3,& b" v8 P+ a; f: L3 E6 ^9 `
# 如果需要的是pip,则yum install python-pip
& L( }" Q' q$ d; M/ o9 F- o* L$ pip3 install docker requests6 B. w$ `! o/ L& r: Z
如下是其中两次报错信息,注意其中的结尾:No module named ‘XXX’。2 C& f/ z: p, M: T8 D5 \9 M/ s3 w8 U
Code
$ w1 _$ }; W2 K% _0 E2 Q! Z v; D$ [
fatal: [192.168.8.65]: FAILED! => {"changed": false, "msg": "Failed to import the required Python library (Docker SDK for Python: docker (Python >= 2.7) or docker-py (Python 2.75)) on controller's Python /usr/bin/python3. Please read module documentation and install in the appropriate location. If the required library is installed, but Ansible is using the wrong Python interpreter, please consult the documentation on ansible_python_interpreter, for example via `pip install docker` or `pip install docker-py` (Python 2.75). The error was: No module named 'requests'"}
" `! z y! H% X z1 Gfatal: [192.168.8.65]: FAILED! => {"changed": false, "msg": "Failed to import the required Python library (Docker SDK for Python: docker (Python >= 2.7) or docker-py (Python 2.75)) on controller's Python /usr/bin/python3. Please read module documentation and install in the appropriate location. If the required library is installed, but Ansible is using the wrong Python interpreter, please consult the documentation on ansible_python_interpreter, for example via `pip install docker` or `pip install docker-py` (Python 2.75). The error was: No module named 'docker'"}
7 M9 Q. `! q; Q2 Ansible构建并运行Docker镜像, H' n( T* E: ?7 `# P0 m- a
通Ansible提供的docker_image模块可管理Docker镜像(比如构建、移除、pull镜像),使用docker_container模块可管理容器,比如将镜像运行起来成为容器。
- u: w7 A. Z8 K% u. Y. M: z: y对我们而言,一般都是在已有镜像的基础上通过Dockerfile来定义新的操作,然后构建出自己的Docker镜像。所以需要提供两个文件:一个基础镜像和一个Dockerfile文件(基础镜像不存在时会自动下载)。如果使用Ansible来构建镜像,那么这个Dockerfile文件需要能够被Ansible读取,比如可以放在Ansible playbook文件的同目录下。
- j8 W1 y" x5 g* a/ n- N8 O为了演示以下Ansible构建Docker镜像,此处已经写好了一个非常简单的Dockerfile,该Docker镜像是在CentOS 7镜像的基础上添加nginx,然后让nginx运行起来并提供cowsay页面。4 t2 {! @8 G. @' |8 Z
Dockerfile内容如下:
3 D3 _9 r, e5 i4 aDockerfile- p3 e, _4 S) D: A9 D ?, c! z
2 C* K& {) C9 R
FROM centos:centos7& v) S9 s/ `4 |( r0 L
LABEL maintainer="test.com"1 Y( P, d" w8 J p
RUN rm -rf /etc/yum.repos.d/*.repo && \- p# f8 @# G/ g5 ]. W) _% w
echo -e ' \. _# n2 j, V% w% h3 g; c) B
[base] \n\
1 K3 K: W" t3 u% Aname=os \n\% B* O' D5 x9 N2 k' F
baseurl=https://mirrors.163.com/centos/$releasever/os/$basearch/ \n\# j" O) l* k4 e/ t
enable=1 \n\
/ @/ b: G0 p$ F- b3 Ugpgcheck=0 \n\
& w! F! E9 Y2 S! a6 _$ S% i( S[epel] \n\
) u' L9 S4 @& t/ g1 L) Y8 g3 }name=epel \n\
4 ?* [7 s6 @/ s U( i6 i% u2 \baseurl=https://mirrors.163.com/epel/7Server/$basearch/ \n\ j% a4 d" _. S t
enable=1 \n\: V! x9 L( n9 \6 |6 K4 x7 ~5 y
gpgcheck=0 \n\
; u9 T& R% P; u0 m' >/etc/yum.repos.d/base.repo && \
" n1 @4 f4 }' R2 @. d0 w yum -y install cowsay nginx && \
" N" s& r& f S% | rm -rf /usr/share/nginx/html/index.html && \
( k; ?2 D d7 F1 b6 Q2 O P cowsay test >/usr/share/nginx/html/index.html && \4 g4 F* O3 Y1 _1 \% A7 A
echo 'daemon off;' >>/etc/nginx/nginx.conf && \
$ t+ d: `- ?' m yum clean all
2 e7 ]& ]6 U: G* U3 {& K - t& E( t( p `- R5 {; i
EXPOSE 80
* C" {) O6 F- N6 x4 QCMD /usr/sbin/nginx [7 W" D ?! V" W) Y4 J
然后写一个Ansible任务文件,假设名为build_and_run_image.yaml,内容如下:- E# @! P D2 z6 S
Yaml
: |2 c. o; k# `; C8 {" o6 h% e0 Z9 Z+ T& f! i d2 E+ g( I
- hosts: docker# }( G5 Y, K1 h4 ^
gather_facts: no+ W G1 Q) u$ L* z8 A
tasks:
4 I2 P: X# V: {2 w( a* ?% A" M( c, F - name: scp Dockerfile+ b# w- d, t2 S6 K- p, F. G8 Y
copy:
/ P; Q+ x7 J/ m src: Dockerfile" ]- c) e1 }: e/ |( x( c
dest: /tmp/Dockerfile& }- E3 u, ^0 d4 S; Z' P" l! |
- name: build Docker image centos_nginx:v0.1.1
% Y+ @$ f% x3 |+ E& g docker_image: 0 i% [' e+ z8 }& v
name: centos_nginx7 T1 C. k! O( l, e& ^/ A# J
source: build R( \; O) z1 K- E# R7 Q" {2 p: l
tag: v0.1.1
5 s' ]9 {1 M3 B+ U1 g build:
3 }$ q; V; o# f$ t path: /tmp* r3 g+ b0 P& g/ I' A8 Q9 [
pull: yes1 W1 F- N# p x6 @3 S
- name: start centos_nginx# y4 r0 ^7 L5 P: r) ^& @
docker_container:
5 L, j/ F$ F; d7 n( ^% ~ name: cng
% ]' `; M7 C, a* E1 A8 ? image: centos_nginx:v0.1.1
, [6 i6 N) @! i7 a" N" G7 X ports: 8080:80
|* j8 s" b, ~% M# h9 W$ f8 J state: started7 |2 g! K5 w! @$ s) l
Ansible执行完成上述任务后,可直接在Ansible端使用curl来测试页面是否可获取:( m4 H# T6 \% D( C7 I6 O8 ?
Shell
2 S7 I, ~$ _. Z4 m# J3 o. V5 C4 y# }: Z
$ curl 192.168.8.65:8080- F! n2 m3 _" [. T
______________$ \9 l% ?; j0 r) ?5 _0 n
< Junmajinlong >& `* e/ s: Y. L1 X1 l& l6 i
--------------
* T0 H a7 Y U2 X! ^ \ ^__^
3 E z- I$ H r' Z' z) J2 s \ (oo)\_______# Z' v5 G% S2 c3 I, N% y
(__)\ )\/\
7 S, B# c0 u( [0 H ||----w |
2 w4 C4 U9 y3 g8 Y) w# T0 S' a || ||
& X; P1 f3 ?9 j5 g这里对上述两个模块稍作解释。
1 u- o- [" L' {8 Q$ w% `8 W对于docker_image任务来说,通过sourec: build指令来表示这是一次镜像构建操作,source指令可包含如下值:* D, g+ h/ \! }8 n b
build:根据build指令的path参数指定的Dockerfile构建镜像; Q' |; m' b6 T0 n
load:从镜像tar文件中提取镜像( T$ _. x# ?5 U$ v( o
pull: 从registry中拉取镜像0 N9 Y! c, [. _
local:保证docker端已经具备指定的镜像
" h! ^, b; g2 q6 v+ s- }: C2 M对于build指令来说:
7 U- l8 {" g, K5 e/ r! Ipath:指定构建时的上下文目录,该目录要求包含Dockerfile文件
- v" X! b$ C1 F# V5 q' Kdockerfile:明确指定使用哪个Dockerfile文件,而不是默认的上下文目录中的Dockerfile文件
0 l6 d/ f0 C" k+ {pull:构建时是否从registry中拉取基础和中间镜像镜像 L. ^% }( P+ v$ c3 u) ?9 P
cache_from:构建时使用缓存的中间镜像
/ a8 i5 y7 g$ V: K* I3 X7 o" |args:可按照key:value方式指定镜像的参数,对应于Dockerfile中的ARG指令,例如listen_port: 8080. }7 u, W2 w/ @/ v; i
其它指令应该都通俗易懂。
1 `& N9 C$ q* W( y* H6 u构建镜像完成后,可使用docker_container模块启动该镜像。该模块指令非常非常多,几乎包含了docker container命令的所有选项功能,但是熟悉docker命令,这些指令的用法也通俗易懂。比如,指定卷和环境变量:8 A! _5 E: {9 d+ o" F' D+ P
Yaml
6 P' z/ D( {5 {- N( \' x6 ^4 |6 @* l5 H
0 ]2 E9 I9 Z; a
' p! X. e6 B/ o- name: Create a data container0 y- f& X+ J8 r7 o) n/ A P v H
docker_container:( X/ f$ ?( b5 z5 b3 L- V
name: mydata
3 N+ s" b% ]6 _% J4 c O1 @: g image: busybox) r x) B7 u: l, N. s- w. s1 Y
volumes:
3 P: f% g+ g |" d# M% U1 ? - /data
e! U S2 b4 \% n- U6 i- name: Restart a container1 K3 G6 O, F+ j1 S
docker_container:
! P, z. D% y4 n( R& R! N name: myapplication
2 h' C9 m K+ ?- [! e image: someuser/appimage7 ? ]# o) B+ {6 e* V; a
state: started
* n) T( k6 o2 y2 r restart: yes
/ Y }/ q" Z1 u devices:
$ D- {/ [3 H: D5 U* u% y - "/dev/sda:/dev/xvda:rwm"5 |4 v9 n# g) Y
ports:
0 h6 R ~" D+ d" @7 @" `9 x - "8080:9000"
/ j( E: T* i7 G! e( y. N: W) S: U - "127.0.0.1:8081:9001/udp"
8 D+ k3 F$ k& a env:
- u: X2 w, e6 K ^9 P SECRET_KEY: "ssssh"
7 t" \: r$ [ m m" f% ~3 o BOOLEAN_KEY: "yes"' D, C, k- i. u6 |2 v3 W; N' p
3 无Dockerfile启动镜像并连接容器7 e9 o. m, r! O8 ?2 s5 S4 W
在上面的playbook中明确使用了Dockerfile来构建镜像并启动镜像提供服务,但因为Dockerfile自身也是基于基础镜像构建的,所以可以省略这个构建过程,而是直接启动基础镜像并连接到启动的容器进行操作。& q2 R/ `+ r$ y8 \1 [+ n
下面实现与上述示例相同的效果,只是不使用Dockerfile构建。5 s2 j+ V9 B$ l8 S1 A
playbook文件内容如下:
3 h5 w( T ^) _Yaml' q) t G$ F0 s _7 R; o0 N$ k
* l% [3 K6 z- y9 x$ p. `
---
. p; y m# f5 w- name: start image # i! y1 Z0 i9 L
hosts: docker
" K- B, ~- m. s5 a7 x gather_facts: no
* m: g* y7 }% t) y' A vars:
9 I0 W2 B5 g0 M1 c0 _ container_name: "centos7"* {% ]& F. d Q$ w8 a
tasks:- o8 Y/ z& A5 K$ t6 \. S* y
- name: start basic container "centos7"
+ Q/ G, E. b7 }9 l/ t3 O$ G docker_container:
) C; N% f. y% t7 H/ Q name: "{{container_name}}"- l2 j3 g! d& Y4 d/ I. a
hostname: "{{container_name}}"5 X4 O7 |1 v5 ?! m6 F1 |8 N
image: centos:centos73 n! D3 D! ^: s9 o/ q. F, W# V2 b( u
ports: 8080:801 V5 u+ \( y. ~ @4 \- u
state: started
' a+ C! p6 M( j: A' ] auto_remove: yes
& p8 N( }. O0 j% o( F- y command: bash
+ A6 y' V5 }- N; g" Y! X tty: yes
; ^3 Z' d% M. w+ [9 A% u . a- ?5 l: ~7 s5 o4 L, \
- name: add container to inventory0 B, ?& n* s, V: R% x
add_host:
' M) o: t4 m& {( _' @ name: "{{container_name}}"
* {8 s8 F9 {/ F9 [2 X# N. s8 T: o ansible_connection: docker
+ _% o4 x4 w# o$ L; g ansible_host: "{{container_name}}"
: I8 a& w) Z: x+ X0 C) S ansible_user: root
. C [ \: ]- [ groups: containers( a) b" ]. n7 d- L& @; K
' D E3 u/ I3 h" s% \- name: do something in container: E, e+ l9 m& e- E; t& a
hosts: containers1 A& f; w C/ \* S; l" w
gather_facts: no3 G# t: G0 w9 G# Z1 w, y j
tasks:
# I, ?) m% A. { - name: install python if needed
$ v3 G0 \ n1 L raw: yum install -y python$ P! B: D- S6 q9 i
- name: remove all repos exists+ z+ U# ~- s6 r, U
shell: rm -rf /etc/yum.repos.d/*" K% X3 t# M% o6 J0 `' H
+ G8 d F6 V. L' b$ R
- name: add os repo and epel repo/ R2 P) v6 M8 }; A, Q% ~
yum_repository: 9 e5 V& w% M, R* {+ e1 j
name: "{{item.name}}"8 a! y! G) V p# k7 A4 \
description: "{{item.name}} repo"1 p1 t9 Y# w5 h4 P8 W. {
baseurl: "{{item.baseurl}}"
5 j% B' C3 k" M# a1 T file: "{{item.name}}"& b& D3 H5 A2 u8 l& p+ n8 P z
enabled: 1
# c, G _# V% J3 [5 O: P8 l gpgcheck: 0- {, D- G- Q1 S Z9 n8 A; ^3 @) \ b
reposdir: /etc/yum.repos.d
. S5 U& A, A. d9 I loop:
+ T4 _$ J7 V8 O2 T - name: os
2 c1 Y# ~ u: D0 \' z8 M4 i" H baseurl: "https://mirrors.163.com/centos/$releasever/os/$basearch"
) c9 _: s; i+ W* z3 D. G2 P1 q! B: ] - name: epel6 J1 p9 L5 E* _3 m5 t
baseurl: "https://mirrors.163.com/epel/$releasever/$basearch" 7 r! ^4 l2 U4 u! y7 w; V
- name: install nginx and cowsay 0 c0 Y3 g& f" d g0 F
shell: yum -y install nginx cowsay
3 e% G0 A0 r* d- k/ Q . z3 U# u' a/ B3 {+ m- q) ^+ v. r
- name: configure nginx
# s4 e& G5 A* k- q7 s/ y6 @: Q0 v lineinfile: 6 m) V+ R/ i1 b- D# S7 K- s) T
line: "daemon off;"
* p' X; b# a" `* c dest: /etc/nginx/nginx.conf
" y7 V- I, E+ A6 d0 Y 2 S L" \6 v& f* q; C. k" O8 S
- name: change index page- q5 [2 f" m; B7 u5 [0 Z
block: ! u: s w# O, n
# 先移除index.html,因为它可能是一个软链接
% e7 ^; U' }/ ?) _& \ - name: remove old index.html page3 H# a$ U( h) T/ I" O1 ~
shell: |' U5 M {: a( t( m; @6 r5 l' ?
rm -rf /usr/share/nginx/html/index.html
6 m" u8 c8 v# M3 U& u0 p cowsay test >/usr/share/nginx/html/index.html
! d ]: W4 [9 \2 d9 R8 _1 O. R3 g3 X" X - name: run nginx
; [3 [4 K' I: @* X9 s; @ shell: nginx &4 X3 Z# A6 J# q# A/ U
在执行上述playbook之前,需要先在Ansible端导出连接方式docker所在主机的环境变量,比如Ansible连接到远程docker时,使用tcp:$ W( I0 p- w0 ?. v6 v4 X
Shell
3 G; e8 k# x* X
+ r5 ?7 Y' U' U' ?- a* `+ i( a' D
$ export DOCKER_HOST=tcp://192.168.8.65:2376
; F7 j0 e) X* f6 f8 y% y8 R, \( l$ ansible-playbook -i inventoryname playbookname.yaml
( B9 L6 X/ O; v3 z: F' e4 c上面的playbook任务中,首先启动docker容器,然后使用了connection: docker连接器添加该容器到containers主机组中,以便后续的连接。之后在第二个play中连接到containers组,安装Python(CentOS系统都会带有python),配置yum源,安装Nginx和cowsay,并启动nginx。任务流程比较简单。$ f2 y- ^ A* B+ J7 n2 K
唯一需要关注的是add_hosts添加容器节点到inventory时指定的docker连接方式,这里不能使用默认的ssh连接方式,因为目标容器不一定开启了ssh服务,也不一定能和外界通信,而使用connection: docker连接方式,Ansible将会先ssh连接到docker服务所在主机,然后通过docker container exec的方式连接到容器内部。2 F5 u8 G4 Q9 h% L
docker inventory
. q* y/ W/ e& f: D$ I. f" G1 Y8 y& iAnsible为Docker提供了动态inventory的脚本。可下载该脚本:
5 O7 f. }6 J. v, S, S" bShell% u- Q1 r& \# B* S5 v- q- w( c/ K
$ |& F1 N6 @( g4 y x9 z3 o0 Q5 F0 V/ d7 q( ~
wget https://raw.githubusercontent.com/ansible/ansible/stable-2.9/contrib/inventory/docker.py
4 J) c6 a! D. o" O- H& |chmod +x docker.py4 w% x# L/ G. z
执行该脚本测试:6 E. _9 u, _. B) ~8 C$ Y
Shell. s8 T6 Y6 Q* e1 D
$ i1 M% Y5 [* z) y8 aDOCKER_HOST=tcp://192.168.8.65:2376 ./docker.py --pretty
5 V1 r% e; _. X( q% a6 F或者直接在ansible命令或ansible-playbook命令中使用-i选项指定:, X, v7 c" A: @: ]
Shell
* Y6 t( a' ~2 S0 q: f9 ~6 O
5 B5 R8 S7 w6 U& ~6 v5 N h {ansible-playbook -i docker.py docker_containers.yml
; n! b4 f$ }, w) k4 其它Ansible容器管理工具5 O1 q, K2 E& h2 W2 U
Ansible除了在官方提供了docker相关的模块外,还有一些第三方的工具可用来管理容器。. q$ ]0 [; K6 A; S. N2 O4 F
比如ansible-container、ansible-bender、Ansible Operator,它们需要单独安装,对于ansible-container来说,在之前几年比较知名,但是作者现在已经将该项目废弃,据作者本人所说,ansible-bender和Ansible Operator更好。1 q' V* e, i) K" E# |
ansible-bender:* O" e4 N2 `3 U* c1 E4 ]+ w' v. R
简化Ansible Playbook构建容器(注:此容器是符合OCI标准的容器,docker所构建的底层容器也是OCI容器)0 m: Q5 @# f# ~: H- r+ @
地址:https://github.com/ansible-community/ansible-bender) K3 ~: O% ]/ f- s: @, t, G* V
Ansible Operator:( |6 c- _: U' C7 ^$ Q3 ?
是Red Hat Ansible Automation和Red Hat OpenShift团队联合开发的用来将容器部署到K8s上的工具
1 g" [1 M0 _; p( p) I地址:https://learn.openshift.com/ansibleop6 |8 X+ a' h3 A. M) G( [3 d
5 Ansible管理OpenStack* m. |! n9 e" U) E- _) r5 |* x
OpenStack可整合一台或多台物理计算机的资源来按需创建、管理、配置、删除虚拟机(在OpenStack中,虚拟机对应的术语是”计算实例”,但后文都以虚拟机来描述),对OpenStack提供者来说,提高了硬件资源的利用率;对受益用户来说,可按自己的需求申请带有各种性能、各种资源配置的操作系统,比如公有云的模式,就像去网吧上网一样,想上多久、想体验什么配置的主机都按需付费来享用。
/ p3 O2 Y5 V9 l7 E2 e对于OpenStack来说,Ansible几乎是全程参与其发展的,因为从OpenStack很早的版本开始,就已经逐步支持通过Ansible来配置管理OpenStack,而Ansible管理OpenStack相关的模块也随着OpenStack的版本迭代在不断更新。目前为止,Ansible官方提供的关于OpenStack的模块已经有五十多个,下面是Ansible官方目前提供的模块列表信息简介:
) M+ q9 Q. v2 W4 B+ PCode
! O9 h' L: ~ T( I7 M! j& g8 G* d
os_auth – Retrieve an auth token
M% {# t; X* B/ P' jos_client_config – Get OpenStack Client config
; [6 i3 C h$ k" ros_coe_cluster – Add/Remove COE cluster from OpenStack Cloud
: l7 A8 [: o `, o" Z* Ios_coe_cluster_template – Add/Remove COE cluster template from OpenStack Cloud5 m$ P* |' J. W( }( g i X
os_flavor_info – Retrieve information about one or more flavors
/ K) y( ]; m" E. o- b6 k3 Xos_floating_ip – Add/Remove floating IP from an instance- P0 x* j1 z8 F6 e
os_group – Manage OpenStack Identity Groups
8 W; C9 n2 Z# P" [+ jos_group_info – Retrieve info about one or more OpenStack groups9 X* _# S z* {0 w( q1 c
os_image – Add/Delete images from OpenStack Cloud
) n. g& q! V- \9 p4 Qos_image_info – Retrieve information about an image within OpenStack j6 [7 L1 E1 U
os_ironic – Create/Delete Bare Metal Resources from OpenStack+ X" m0 Q! W# L/ } I; O
os_ironic_inspect – Explicitly triggers baremetal node introspection in ironic; p+ N# T, U# S) }
os_ironic_node – Activate/Deactivate Bare Metal Resources from OpenStack
2 z( g+ z1 I' a$ F7 R! qos_keypair – Add/Delete a keypair from OpenStack
, l, o2 H* m$ n- Pos_keystone_domain – Manage OpenStack Identity Domains" m' @% J7 w# ]0 s
os_keystone_domain_info – Retrieve information about one or more OpenStack domains
r2 G1 d! Y1 x! J$ Pos_keystone_endpoint – Manage OpenStack Identity service endpoints7 e3 G2 t1 z' ^ @+ H7 j
os_keystone_role – Manage OpenStack Identity Roles* k8 C) S! k( |4 |* V' z: i
os_keystone_service – Manage OpenStack Identity services1 P" `8 t" a) J/ b2 q( o9 C& E
os_listener – Add/Delete a listener for a load balancer from OpenStack Cloud
. U: i2 E, O$ ?" S( h$ o; |os_loadbalancer – Add/Delete load balancer from OpenStack Cloud
/ `4 c* y! M, V+ C9 Fos_member – Add/Delete a member for a pool in load balancer from OpenStack Cloud- M7 u }4 p6 \+ m- x& Q: `9 |
os_network – Creates/removes networks from OpenStack
( V1 x. j, x( w! Cos_networks_info – Retrieve information about one or more OpenStack networks
; P# w' o+ z5 Q6 }8 Ros_nova_flavor – Manage OpenStack compute flavors
6 m+ ~+ n0 `! w5 `3 O* V& `6 `os_nova_host_aggregate – Manage OpenStack host aggregates/ a9 [' k L# E/ N4 X
os_object – Create or Delete objects and containers from OpenStack
% ^! G7 V: ?% l1 |os_pool – Add/Delete a pool in the load balancing service from OpenStack Cloud' B7 q2 P$ b& p+ c" N/ x
os_port – Add/Update/Delete ports from an OpenStack cloud
1 Z* z& m A6 {" h8 L6 |/ pos_port_info – Retrieve information about ports within OpenStack
* M# u0 E6 v) xos_project – Manage OpenStack Projects
: v' ^' L o! Q+ yos_project_access – Manage OpenStack compute flavors access
6 I! ~0 M; Z0 S8 @1 G" Mos_project_info – Retrieve information about one or more OpenStack projects7 ~2 |2 l$ w/ V- V# b! j0 v9 C
os_quota – Manage OpenStack Quotas5 K( ?" L5 E% h; i
os_recordset – Manage OpenStack DNS recordsets. l6 b' H! }$ ^& [% G" `* J! ?
os_router – Create or delete routers from OpenStack/ ?+ l" U% N' q( y6 d5 B D h; i
os_security_group – Add/Delete security groups from an OpenStack cloud' q* s! }) ?& H5 F
os_security_group_rule – Add/Delete rule from an existing security group
. u& {* Y8 |2 \- gos_server – Create/Delete Compute Instances from OpenStack) ~. ~6 q" Z% S3 t0 P" [1 Y, e$ ~" ^% w. y
os_server_action – Perform actions on Compute Instances from OpenStack2 ~7 q/ K6 @! q4 s6 @
os_server_group – Manage OpenStack server groups5 ^% p& C7 ^4 V: ~3 s
os_server_info – Retrieve information about one or more compute instances: ]- S: n8 R8 J
os_server_metadata – Add/Update/Delete Metadata in Compute Instances from OpenStack3 \- G% y; b5 F8 S' s9 |) ?
os_server_volume – Attach/Detach Volumes from OpenStack VM’s7 t9 l# }& ^. x
os_stack – Add/Remove Heat Stack$ Y7 y9 v B; l/ k% ?9 O
os_subnet – Add/Remove subnet to an OpenStack network: \, X# T; L% q# A4 G/ O/ d
os_subnets_info – Retrieve information about one or more OpenStack subnets
/ I5 u3 I5 ^1 p: Bos_user – Manage OpenStack Identity Users% A( Y( ]: S. ]& X% C5 @
os_user_group – Associate OpenStack Identity users and groups
7 @1 [# z+ a5 {- }os_user_info – Retrieve information about one or more OpenStack users
. \6 ^5 ]8 y3 zos_user_role – Associate OpenStack Identity users and roles
8 Z/ X( j& E: kos_volume – Create/Delete Cinder Volumes
7 [. }% _! b# x3 z, d' Fos_volume_snapshot – Create/Delete Cinder Volume Snapshots7 {0 V7 J- a4 q$ k+ f: H; Z
os_zone – Manage OpenStack DNS zones
0 Z! w3 O, ]. j R虽然看上去很多,但大致可总结为Ansible可对以下资源做管理:
( U/ v' ^: h1 I$ {5 } [(1).计算资源
+ I/ a. N* t( s( _8 t(2).镜像管理. s9 N1 S$ b) L; p. n
(3).账户管理和账户认证6 a0 e( b% H" O
(4).网络管理
6 i2 D k' U0 q. Q" g7 {' w) Y(5).对象存储管理$ M% M9 X/ g$ c( X
(6).块存储管理
# `) q0 \+ L* c对每种资源的管理可分为四类操作:
7 v& R. z6 w% a1 X. k(1).获取管理目标的信息4 A" Q: O9 N* v5 C# E' \6 I! g
(2).添加管理目标
& \3 w5 a& y! T8 M6 n6 o(3).修改管理目标的属性- K: ^% r6 S3 f; c4 S6 j
(4).删除管理目标( B) p6 r8 c! U. @8 ^# ~( q" D
即增、删、改、查。
9 p7 j9 e7 u5 s0 P' G$ X此外,由于OpenStack自身已经跟踪了其创建的每个虚拟机的信息,所以Ansible还可以直接从OpenStack中获取这些虚拟机的信息,比如从OpenStack取得某些虚拟机信息来构建动态inventory,这样就免去了手动提供虚拟机inventory的麻烦。
5 T) A/ B9 N3 @本文不会介绍Ansible如何操作OpenStack自身(比如添加网络、上传镜像等),这和管理普通服务做的一些基本操作没任何区别,不同的仅仅只是做不同操作而已。本文会介绍Ansible管理OpenStack虚拟机时最常见的两种场景需求:
5 b0 S, @. r, G9 m0 ^8 v(1).使用Ansible创建虚拟机,然后像平时管理远程主机一样管理这些虚拟机,最后删除这些虚拟机
3 p. O9 W. V" H(2).从OpenStack生成动态inventory i) g4 N X5 I9 L1 A# ]
14.2.1 创建虚拟机7 Q; G* M* p. m1 P/ O$ }" @
OpenStack管理虚拟机相关的模块都以os_server开头,目前包括如下6个模块:本文大概只会用到os_server模块3 }( U& C/ d/ Z! I
Code
9 `7 A6 r% I& r+ U9 j2 F/ n4 F, V
, Z; ^9 [+ y* _+ ]* X: r4 E6 oos_server – 创建或删除虚拟机0 Q, [9 h M# `1 H' C% C& ]
os_server_action – 对虚拟机做一些操作,比如虚拟机的关机、开机、重启、暂停、恢复等操作& R4 u8 m+ I2 o4 `
os_server_group – 管理OpenStack虚拟机分组,比如测试环境的虚拟机可属于test组,生成环境的虚拟机可属于prod组
& A1 _: o& J* |! s5 e5 \2 ]6 Qos_server_info – 检索一或多个虚拟机信息,在Ansible2.9之前,该模块名称为os_server_facts,用于检索虚拟机facts信息
0 D- B# F. T$ z. q4 H) _& Z. jos_server_metadata – 增、删、改虚拟机的元数据信息,比如设置虚拟机的主机名、虚拟机设备信息,如网卡配置、磁盘路径/dev/sda 4 m3 D0 ]% w: ]9 }( r
os_server_volume – 附加、剥离虚拟机的卷3 b/ g7 R) W( k# I
这6个模块都要求先安装好版本高于0.12的openstacksdk包,在CentOS 7中只需执行如下命令即可:6 s" D6 @5 @% q' @$ W: ?% ^; j
Shell: d3 ` Y: [6 e
0 A+ U: S5 w/ S+ w' e2 T9 l8 Q
$ pip3 install openstacksdk8 m% U( H4 H$ a3 \
为了让Ansible连接到Controller进行管理,需要添加Controller的inventory信息。假如OpenStack的Controller的IP地址为192.168.8.65,可inventory文件openstack中添加如下内容:( W0 S- b/ G9 N. G5 l# ?/ e
Undefined0 e# z$ L9 [, s( s
1 L. m6 j7 B" H" t9 _[openstack_controller]
# o# [' e8 b- D% l. ^* I6 N192.168.8.65# M0 r/ t" r3 s$ Y& A! D
配置Ansible段和controller的ssh认证互信可自行配置,此处不赘述。
3 i. k9 p9 o" j. b& y然后就可以编写playbook来创建虚拟机,假如playbook文件名为create_vm.yml,其内容如下:
* U9 l5 z6 K3 bYaml9 R# _# o* F. {% [( g
8 J* s9 }- p9 L! W0 v! a- name: create vm
8 s4 U- g1 K: ~. C0 h hosts: openstack_controller
4 L( [1 M3 `9 x, V gather_facts: no0 l. B+ Y6 F7 Q5 W% G# @7 R# G
tasks: 8 m+ y( L# g5 O$ O6 R \) m1 V$ ^
- name: Create a new instance
9 P+ w6 t; @- }+ u& m ] os_server:
. C9 x3 W1 v" ~# d8 ~6 f& d state: present# D8 t/ Q7 E% z, O
auth:
* h5 {' V$ t( O9 \* S8 {) k$ v auth_url: http://192.168.8.65:5000/v3; z# y5 M. p* j( P, _5 N
username: admin. v0 k6 G& o8 O8 O- s
password: admin123
7 W7 `8 L O3 n- r project_name: admin( L \! _$ g+ k; d# J
project_domain_name: "Default", M* M- W* T# r5 A( d- s; ]
user_domain_name: "Default"' C* [" D6 U7 h- N- W' d
name: vm1
6 @7 M" |. t* S( F image: "CentOS-7.9-x86_64"
4 \2 ]6 L, P: q2 h- q key_name: ansible_key
2 j6 D3 z# I \- j9 s" G6 u timeout: 200
a$ z9 g. c2 U7 I2 ] flavor: m1.small9 B+ K+ l, f& u! N1 J( \6 L
network: 'ext_net'
% y+ _) I+ V V D( W5 C$ p wait: yes
) j, ?$ d1 G! p# ~5 |. A7 v meta:9 m9 k) p2 F, }
hostname: test18 K9 N2 G; x( N, a8 V3 h J
group: test_group
$ b/ v0 P. u6 Q( }3 v) F8 ? userdata: |
1 a8 u `% ?; V- p2 c {%- raw -%}#!/bin/bash
Y; z- E- F0 G3 s0 c: H cp /home/centos/.ssh/authorized_keys /root/.ssh/
- x+ y" U0 `" z/ C) V0 ] {% endraw %}
3 C: M; P& {: ^2 Uauth部分是认证相关信息,name1表示创建一个名为vm1的虚拟机,image、key_name、falvor、network都是OpenStack中已经配置好的。这里还同时设置了虚拟机创建出来后的主机名为test1,并加入到了test_group主机组。
0 X, v7 `, d5 A* B# F因为是CentOS镜像系统,该虚拟机创建出来后,默认登录用户名为”centos”,而且默认不支持root登录,为了后续可以使用root登录,上面使用userdata定义了该虚拟机创建后自定义的操作,即将保存的公钥信息拷贝到/root/.ssh目录下。
! L# t# r5 }; ]& [注意os_server创建虚拟机任务中的一项wait: yes,它是默认选项,表示Ansible会等待虚拟机创建完成才会继续执行下面的任务。, |: A7 A! ]# D( B7 D, e1 r
因为所有的模块在连接OpenStack时都需要进行身份认证,为了简化playbook中的认证内容,将上面的auth选项段落的内容保存到OpenStack Controller的~/.config/openstack/clouds.yaml文件中。例如:
$ P: k0 W* X9 d0 V* C' UYaml
6 r* M4 ^. B5 E2 j2 T+ a2 C8 V
! k' n2 I( v' I( Y# Pclouds:
" k* h. T7 M( U8 P mycloud:
. o* m5 @$ X+ N# t+ M) l h' | auth:2 g b0 b6 g: }7 r) a
auth_url: http://192.168.8.65:5000/v35 v5 m3 C8 t' t9 r# w8 M+ O) h& l
username: admin2 a8 x" e. g0 R t
password: admin123
6 M) }. \& ^; R9 q- Y( l project_name: admin
* X- y' ?6 F# g/ J; x1 i project_domain_name: "Default"
6 y8 k- J' i+ G, G* S m user_domain_name: "Default"- ^8 h" E0 N3 D( C( P1 y8 F
以后在模块选项中就可以省略auth,而使用一个cloud: CLOUDNAME即可:
" V# t% }0 `. N0 cYaml. V. E: l6 A" M u& T, |& @
2 m$ y* F! d, j7 Y1 m
tasks: ( h+ ~ J" T6 w
- name: Create a new instance- B- {; @# b! M% A+ a
os_server:
$ ^3 U! {, v! b' n$ X* A$ { clouds: mycloud. R3 F; Y& Q2 S* {. H+ ^
state: present$ n# w2 V+ `" f' ~. ~* G
name: vm1
0 O+ X4 c* W, j; T7 o image: "CentOS-7-x86_64"! f+ [. l7 g$ M% B1 i
key_name: ansible_key
: [: U# w l2 Y2 j9 o timeout: 2009 H) r8 y% g8 w z! n
flavor: m1.small
- d. m1 f/ ^# j" C network: 'ext_net'" }7 l/ Y5 J8 p: ?+ i
wait: yes+ y/ f+ N: R/ ]/ U R$ }3 j6 Q8 T
meta:: n. D3 h& o& s
hostname: test1/ [& i1 D, d) J, z+ R
group: test_group
+ p+ q3 a% Y. P但是要注意,将认证信息以明文方式写入文件是不安全的,可以使用Ansible的Valut加密。不过OpenStack的dashboard中也已经提供了一个环境配置文件,可以先按照如图所示的位置下载:2 k* R* W) u' l( P
+ j" N/ q& {5 Q0 m( r然后以source的方式执行下载到的admin-openrc.sh脚本文件:
/ j K9 ?" o' }/ L nShell4 e( b$ |% t6 d& D; G |. F- r( Z+ a
: l( b* N, x! ?, u: c1 s( C
source admin-openrc.sh
5 u# Y7 G/ b3 G* b$ T" Z& A7 i执行完后,Ansible的OpenStack相关模块执行时,auth和cloud指令都可以省略。# X ^( _1 [6 T) L6 i( O
上面只是创建一个虚拟机实例,但很多时候可能需要一次性创建多个虚拟机。可以将每个虚拟机相关信息定义到一个变量文件中,然后去遍历想要创建的虚拟机实例。例如:
6 A( I+ r W+ _- k0 ], {Code
; v) j( R1 H! s5 m( U
$ G- G: \- l# \8 z( R---; X' H/ ]# N0 r; o, \) H5 c
servers:
. [6 j& H" z; i4 G! D - name: vm1$ j7 x0 q$ t; p7 t4 N, Q, _8 K
image: $ j2 S( C, G% T) n+ K; e
flavor: 0 E+ S" {9 w8 z B
key:
8 B! g3 d, E* x/ H nics:
. I, G( K9 }! ~ Y: c( v meta: . d+ W ~* M% U( n
hostname:
" C, K6 Q+ U6 @' u group:
4 T7 P: \, A) P+ ?' q - name: vm2
: J* N# R9 r3 N- X* M- p6 x. M0 c0 _ image: % S! a/ _% N Q* `4 W8 ^
flavor:
; i: i- d0 j) Z! V' w key: ! Z3 H1 g u: ~
nics:
. y5 l5 C6 r4 K meta: / M9 @: k2 T% N9 i' `
hostname:
, q! W- ~: S* y: j; b+ [* v group:; y m, }/ s" r. h
有了前面的Ansible基础后,此处批量创建虚拟机应该毫无难度。' k# X+ J, W+ x) B& {" m
创建虚拟机后,可以将os_server的任务注册到一个变量,从而可以获取该虚拟机的信息,包括该虚拟机的IP地址:
$ C0 T6 @4 q `8 E& UYml
# V9 k3 f! L% d N
3 _/ ^% J0 @$ mtasks: 2 G _3 v* P+ I* k; A$ [; e
- name: Create a new instance& q+ Q9 q- p ]; w( m. h
os_server:4 j( _" f; {9 s1 K5 |) w; F Y
cloud: mycloud$ _" g' P: d8 i, f+ t6 }: R6 [3 W
state: present
- S, O- I/ v" s' F name: vm1
: b& c/ N- D: L2 N image: "CentOS-7.9-x86_64"
; n8 X: h3 D& n- k: {$ Q; ~ key_name: ansible_key
/ d/ f( k. N! Q( ]$ l" G timeout: 2008 E- u% e) O5 b; `* j
flavor: m1.small2 O! y, u( {5 G e
network: 'ext_net'
T# i8 }6 Q( F3 ? wait: yes
8 R% u+ s# ^! p/ B1 ~ _* u2 |! z2 N) } meta:
0 H9 e1 r- x7 I6 J) P) n hostname: test1
2 [ b/ D- |# J! z' D: | group: test_group
8 H8 ~% ^ i( n% T: { register: newserver& o p% y% P- K2 o/ \4 Y. N
+ r4 |1 g$ l1 B5 o, A/ ]
- name: get instance ip/ z; { k; r8 }0 d1 A
debug: 9 q0 ~6 b1 j9 k: z
var: newserver.openstack.accessIPv4
7 o" l" K/ u- x0 T) b' Y有了IP地址,对Ansible来说就获得了最关键的信息,因为只要将新虚拟机添加到Ansible inventory中,新虚拟机便像普通节点一样可接受Ansible的控制。+ l4 e- K* z P7 U; ^
6、将新虚拟机动态添加到inventory
, P* T1 x8 q! E. h! v6 U, Z获取到IP地址后,可以将该节点通过add_host模块动态加入到inventory中:
( w: n! A9 o! h* N# FYaml
% q! B0 l( {, A! w+ ~5 r1 c7 L4 a! Q+ E7 y: _7 Z( M
- name: add new vm to inventory
# S$ z/ t1 K/ E/ M% D# ~8 M! c add_host:
- H8 \& d | u* T0 d name: "{{ newserver.openstack.accessIPv4 }}"+ [. P% W" k. z. G" U* s0 p- }
ansible_host: "{{ newserver.openstack.accessIPv4 }}"
4 h3 h- Y% A6 n" `* k ansible_user: "centos"& q/ q) F7 P" e! d
ansible_port: 22
, Q2 u; E2 K* ` groups: ' A7 f! a0 o& l E/ T
- vm_hosts
6 G) Y0 `) v6 F) x- ?似乎这里的逻辑不太良好?如果虚拟机启动了但是不可连接呢?对于OpenStack创建的虚拟机来说,完全不用担心,因为os_server创建虚拟机成功后会等待该虚拟机可连接才真正返回。但对于非OpenStack的其它云主机实例则不一定,这时应当使用wait或wait_for_connection模块定义一个等待任务。尽管OpenStack中可以省略该步骤,但在脑海中应当要知道有这个步骤。
1 i9 P1 ?* W+ q5 r6 G此外,OpenStack安装的镜像系统可能是比较精简的系统,甚至没有安装Python,所以为了能管理这些虚拟主机,应先使用raw模块安装Python。# w( w0 S+ C1 M# L
Yaml
- N. q8 u' {' }/ x) ~" S- name: for new vm host! J$ `+ H3 s0 g& d/ g4 @5 p
hosts: vm_hosts5 s( }, ?& E O$ r/ t/ \, T
gather_facts: no
, i+ i$ h. M1 g" T" ?4 b tasks: 5 T0 D% f. _" _) R N, `
- name: install python if needed9 k7 K$ |; X5 [- G2 H. G8 W+ l' B
raw: "sudo yum install -y python"4 i8 r4 o. [% f) y& C" Q5 c) z
如此,Ansible便可以像管理普通主机一样管理OpenStack虚拟机。
, [8 x) p2 B( G! A& O! k5 G7、收集OpenStack虚拟机的动态inventory* m$ _% t: T% G/ o! R9 r( n1 i( O
动态inventory一般需要写脚本(几乎是Python脚本)来收集,但即使不会Python也不用担心,因为对于OpenStack来说,官方已经提供了openstack插件,还提供了openstack_inventory.py脚本,该脚本位于Ansible官方github仓库的contrib/inventory目录下,查看文件时记得先选择对应Ansible版本的分支。' O1 F9 d7 R2 Q {( C! _7 {( T- B+ a
下载openstack_inventory.py并设置可执行权限:4 O" l% S3 u- ~$ {1 V1 Q
Shell
. j* T' c. K4 i+ {
6 v; H) P9 x W" xwget https://raw.githubusercontent.com/ansible/ansible/stable-2.9/contrib/inventory/openstack_inventory.py
4 s( C8 S4 I* a9 j% f pchmod +x openstack_inventory.py8 q) m9 F! B2 y1 c% c8 A& s
然后source以下admin-openrc.sh脚本,再执行:
6 ?% u) l4 Z: g8 V2 [Shell' ~ m B" ]" p( ~2 r$ H
6 Z" Y- e* N( Q i- r! I
source admin-openrc.sh
( q( i4 d2 f. ]./openstack_inventory.py --list U5 q+ d. [; W) B
可查看inventory信息。9 V5 i. X+ x6 v5 W
之后要将该脚本在ansible或ansible-playbook中使用,使用-i选项指定即可:9 I+ W5 e' |2 s% N6 a
Shell% y5 g6 T! ~* ~3 T& G8 Z
' T; n3 T7 m6 Q9 y" uansible-playbook -i openstack_inventory.py -m ping
- u% }1 x7 y- u$ }0 t除了使用openstack_inventory.py脚本动态生成inventory外,还可以使用名为”openstack”的inventory插件。要使用openstack inventory插件,首先要在/etc/ansible.cfg中的[inventory]段的enable_plugins中开启script功能:1 l' d) A7 S; L
Shell
# { s. h$ O# d
2 Y+ o, h9 }* v7 h$ grep 'enable_plugins' /etc/ansible/ansible.cfg
# l& t3 r- E% d9 h, t#enable_plugins = host_list, virtualbox, yaml, constructed
( A# ]& _3 s4 C; M& O8 {取消上面的注释,加上script:9 ? [3 K! m8 C/ B" |2 L% Y
Ini
8 c7 N: D! f3 V, P( i* ?: ^3 i4 \& o" N, t, d% u# ]9 p7 C! E
[inventory]
% _2 T3 _( C4 W# A$ |( M. C% E5 Fenable_plugins = host_list, script, ini, virtualbox, yaml, constructed
0 a5 l. r& A2 U5 K/ R# V以后只需在yml文件中加上如下plugin指令即可:
2 w+ d$ q8 n0 Z6 w+ jCode
0 e4 ^9 m5 m% @: {3 G$ e6 R$ b- |! Z. C
plugin: openstack
- A: z* f5 X" y) u
: a1 j3 o4 g4 q7 b6 I, `7 U |
|