|
|
楼主 |
发表于 2021-8-2 10:51:52
|
显示全部楼层
1 Ansible管理docker7 Q, V L7 O$ I+ U
近年来Linux容器技术越来越受欢迎,通过容器技术,可以保持程序运行环境的一致性,快速启动并高效率运行,涉及到的开销也比较小,此外,在系统层次上完成容器级别的资源隔离非常快速。
% B3 I$ U3 v) k3 x- DDocker是管理Linux容器最流行的工具,它为管理Linux容器提供了许多方便的工具,比如创建、销毁Linux容器,还提供了一些除管理Linux容器之外的工具,比如管理镜像、编排。通过它的易用性,Docker已经成为管理容器的最流行的方法之一。
7 `' w8 L6 j! T9 c! H, x0 _题外话:关于容器和Docker
5 w( |7 f. H* D: f! _Linux容器是内核的几种功能组合在一起实现的。换句话说,Linux容器技术是内核层次的功能,Docker只是提供了一系列工具,包括从底层和内核交互到高层和用户交互的一条龙。除了Docker外,也还有其它操作Linux容器的工具,只是对大众来说,Docker是最流行的。2 `, |% d+ s( S+ o
Ansible为Docker提供了一整套工具,包括相关模块、连接插件(ansible_connection: docker)和inventory脚本,因此Ansible可在许多方面与Docker进行交互。例如Ansible可构建Docker镜像、启动或停止容器、组合多个容器服务、连接到活动容器并与之交互,甚至可以从容器中获取inventory。
0 }% s- C! I- P# Q5 [$ {+ k如下是Ansible官方目前提供的和Docker相关的模块:% Q' `/ ]7 y) o0 N0 o6 }
Code
% ?0 ^2 V6 \5 a, `+ I0 S* O5 T- B- k$ u5 s/ a
docker_compose – Manage multi-container Docker applications with Docker Compose
. H* n, c9 T# r4 F( L. e6 jdocker_config – Manage docker configs; @( G |8 D2 P+ ]4 _
docker_container – manage docker containers) B- ]. c* o& a
docker_container_info – Retrieves facts about docker container! V& n' a0 p: t9 ^ c
docker_host_info – Retrieves facts about docker host and lists of objects of the services
8 ^" h! P) R0 L Edocker_image – Manage docker images
) \! h1 x$ i+ k) C+ s* Qdocker_image_info – Inspect docker images
: ~$ h9 F; G8 P$ y$ M( Xdocker_login – Log into a Docker registry
4 \1 v K( l; K, T! o! }docker_network – Manage Docker networks
/ q8 B, m) _" l3 M" vdocker_network_info – Retrieves facts about docker network! e( r4 r8 t1 y; u$ F8 m
docker_node – Manage Docker Swarm node) i: s7 p) b* u0 K, f4 x( _
docker_node_info – Retrieves facts about docker swarm node from Swarm Manager
& q( r9 i, l8 n7 {7 I" i' I' Qdocker_prune – Allows to prune various docker objects
7 t- P: k+ ]" v6 j9 H7 m9 w' Xdocker_secret – Manage docker secrets* k0 r, G; m5 t3 n5 G
docker_stack – docker stack module5 H$ L7 y8 ~- s6 C" F) e
docker_swarm – Manage Swarm cluster
) s8 M6 I2 ~2 o* sdocker_swarm_info – Retrieves facts about Docker Swarm cluster
+ Q; K; i5 J, q3 @# F2 { ]docker_swarm_service – docker swarm service" k1 F; Z8 B* b' b( a
docker_swarm_service_info – Retrieves information about docker services from a Swarm Manager. J) m& C3 |) l$ p0 G! E, p
docker_volume – Manage Docker volumes
) W* ^2 m: u+ O G- x, E3 u; ?/ c: ]8 Jdocker_volume_info – Retrieve facts about Docker volumes7 k j# F+ V1 L! ?; ?
要使用Ansible管理连接Docker,要求安装如下包(注意:Ansible端和docker端都安装,这一点和其它模块不一样,如报错,请自行在两端安装、卸载、升级调试):8 |9 w3 l8 b' g1 O
Shell6 N5 q+ f) L0 P2 g5 i
5 b8 Z( {8 ~& x" j6 i
# 两端都安装,如果已经安装了,则在报错的情况下按需更新
; z4 R) e6 V- o [$ R3 m* j+ n4 K# 此外,根据Ansible使用的python解释器版本,按需决定使用pip还是pip3,
1 ~1 U: @2 z$ y0 ^$ p8 b: M. _# 如果需要的是pip,则yum install python-pip
/ m% F7 [" z% E% [$ pip3 install docker requests8 W/ G( o- f0 f3 U9 G8 m8 m
如下是其中两次报错信息,注意其中的结尾:No module named ‘XXX’。
7 P" i* {6 s9 O1 b% SCode
$ s5 O8 H$ K% i( ]% a/ u# |) Z" l$ P$ R# n1 R/ H1 S/ L
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'"}2 C( ?# c, h, i" p
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 'docker'"}
" L7 ~8 ~+ V; Q7 t k3 N2 Ansible构建并运行Docker镜像
8 t/ }* S# _# }+ X通Ansible提供的docker_image模块可管理Docker镜像(比如构建、移除、pull镜像),使用docker_container模块可管理容器,比如将镜像运行起来成为容器。8 W8 s$ X$ ^5 x U6 k" T' x/ Y. t
对我们而言,一般都是在已有镜像的基础上通过Dockerfile来定义新的操作,然后构建出自己的Docker镜像。所以需要提供两个文件:一个基础镜像和一个Dockerfile文件(基础镜像不存在时会自动下载)。如果使用Ansible来构建镜像,那么这个Dockerfile文件需要能够被Ansible读取,比如可以放在Ansible playbook文件的同目录下。2 g5 `3 A/ Q% @' Q
为了演示以下Ansible构建Docker镜像,此处已经写好了一个非常简单的Dockerfile,该Docker镜像是在CentOS 7镜像的基础上添加nginx,然后让nginx运行起来并提供cowsay页面。* T8 j7 S- O9 O( N
Dockerfile内容如下:
1 N% R5 z" E. h' l; qDockerfile: ?1 r& X# G8 K9 e+ R6 l6 \$ R9 T2 k
& q( v8 T+ o8 {* k+ Q, U1 ^
FROM centos:centos7/ E, I( c1 h1 i6 |7 {
LABEL maintainer="test.com"" p# k+ D2 G8 R4 i0 E
RUN rm -rf /etc/yum.repos.d/*.repo && \
! J; a$ ]# u/ \ @+ O+ { echo -e ' \
! q! j2 @4 q. r" s3 V1 e U: ]3 {[base] \n\2 l" o d4 v# d" M$ f9 z
name=os \n\7 @8 y! y9 P3 n
baseurl=https://mirrors.163.com/centos/$releasever/os/$basearch/ \n\
, x' j7 Q6 u) B$ _. Menable=1 \n\
5 \% m. \ F! o8 t; |$ `gpgcheck=0 \n\
! F! m _7 a5 L+ F' |* P; s0 n[epel] \n\
: a+ l+ ]2 {- d7 @name=epel \n\3 D0 V, g9 d" Z: w
baseurl=https://mirrors.163.com/epel/7Server/$basearch/ \n\
( \$ y, \% E+ v2 w( s0 Cenable=1 \n\! d. G$ W( |# u, Z" w; {. ]
gpgcheck=0 \n\
3 O" \' @( Z2 y# P' >/etc/yum.repos.d/base.repo && \
% X. A+ J4 L0 E( S8 D" H. z yum -y install cowsay nginx && \
8 n- M! [7 F: n rm -rf /usr/share/nginx/html/index.html && \/ N' c' r3 u9 t
cowsay test >/usr/share/nginx/html/index.html && \
% N" g+ j# L3 }4 L/ U+ K) x& ^0 x: R echo 'daemon off;' >>/etc/nginx/nginx.conf && \
$ _/ i, `/ V7 \ yum clean all% ~2 U M- ^$ f0 Y, w w
% H1 z) V: L$ H9 @ N: sEXPOSE 80
( l& J7 U) ~# ~1 a* f) A: i& [CMD /usr/sbin/nginx
N8 i6 r+ x* u! M. Z8 @然后写一个Ansible任务文件,假设名为build_and_run_image.yaml,内容如下:
+ x% H! ^7 @& yYaml6 A Q) S1 D7 |) I
# M3 Q. c0 Z3 S! g$ y1 I- hosts: docker
7 h5 R2 I3 P- ?7 @. ]9 ^ gather_facts: no7 {, |* v; `4 r& m: D. p. R
tasks:
{4 y& \- K9 a% J - name: scp Dockerfile
- u% I7 H: p; i: g- T% V copy:
p1 N. R5 w9 P3 ~% N* M \ src: Dockerfile4 g* ~& u& L0 R' a# Z" T
dest: /tmp/Dockerfile7 L" {. T6 `( w6 j
- name: build Docker image centos_nginx:v0.1.1
" ]9 ~6 |- h9 Y) `1 p docker_image: : J- I5 h8 F( x7 }* k5 R4 y# y
name: centos_nginx$ N# z8 Y+ ?( p
source: build6 {& O9 z+ n$ r
tag: v0.1.1) y* U% M' ~9 \" t' I
build:
& u& Q) k: R4 V/ I' P/ L path: /tmp5 p8 _0 I9 j+ W& s6 Y( H
pull: yes
- G% U% d7 @3 ~ - name: start centos_nginx
9 u& \9 ]1 V. o. b/ e) q' E& _ docker_container:
$ a& c+ j j1 s& \. D& { name: cng& _+ a; i. p, u4 i
image: centos_nginx:v0.1.1! h( Z, j/ |) ]8 O/ D! f& H
ports: 8080:80
( a1 J# j; u6 n# v* @ state: started# g" G6 U% e4 ~6 x: v; h# ?8 D
Ansible执行完成上述任务后,可直接在Ansible端使用curl来测试页面是否可获取:
) b$ ~ E6 W: PShell! c& N4 p" P, K3 m7 I9 ~
/ c+ f4 @; K8 z; o4 i$ curl 192.168.8.65:8080
% ~) i* ~* L+ g ______________: q. b, r/ m- Y4 m) ^5 h
< Junmajinlong >
% b2 {2 q4 @. V# b --------------% {$ k' {6 N8 f. F% Q( E# B
\ ^__^
1 V* Y* p- K. p4 p, j \ (oo)\_______+ y1 ]1 u; n! T0 K. T0 _
(__)\ )\/\2 H4 k! I- i2 ~$ B4 E
||----w |! L7 H$ V9 P5 E0 l* E
|| ||
# P0 ]% `. u5 X' x0 T/ F1 [+ p这里对上述两个模块稍作解释。
. Z& L( ?: y* r% G( X对于docker_image任务来说,通过sourec: build指令来表示这是一次镜像构建操作,source指令可包含如下值:2 w% E- p0 b( b7 S
build:根据build指令的path参数指定的Dockerfile构建镜像
/ ]$ w6 u* {( }1 D/ D; H( _load:从镜像tar文件中提取镜像
: N: t7 H6 I2 M |pull: 从registry中拉取镜像* R$ P5 u5 P2 a" v& _( \3 N
local:保证docker端已经具备指定的镜像5 a5 I& Z/ h9 s0 l- @3 Q9 V
对于build指令来说:
/ S0 c* A ^+ N, E# ?: w6 x* z1 A& ~path:指定构建时的上下文目录,该目录要求包含Dockerfile文件9 Y* j9 C) v0 W* V
dockerfile:明确指定使用哪个Dockerfile文件,而不是默认的上下文目录中的Dockerfile文件
& \- h( V4 v8 R, zpull:构建时是否从registry中拉取基础和中间镜像镜像
, M# H" x6 W$ k7 n/ j4 s: O: C4 ~cache_from:构建时使用缓存的中间镜像% ~7 t" U- R# [+ _1 w; b- w7 b
args:可按照key:value方式指定镜像的参数,对应于Dockerfile中的ARG指令,例如listen_port: 8080
4 H+ ]6 c" s' I' F其它指令应该都通俗易懂。* N. H5 T/ V$ q, g6 Q2 R ?1 k
构建镜像完成后,可使用docker_container模块启动该镜像。该模块指令非常非常多,几乎包含了docker container命令的所有选项功能,但是熟悉docker命令,这些指令的用法也通俗易懂。比如,指定卷和环境变量:
* u2 {0 r8 k! ?/ r" }Yaml1 f8 C3 @8 O1 d3 T$ m' N
( k* f1 L3 E% _9 T* J5 T
9 M$ i, L k% [6 f+ z8 S* m- name: Create a data container
' @) ]: G1 q+ k+ \, _ docker_container:
! P& m9 x' j9 t4 C$ K name: mydata
/ t9 k6 e& `; i3 M3 w$ [ image: busybox# _- [+ M$ y) u }' r
volumes:
: A0 g' e' g$ s+ G- b" @& c( [ - /data8 Y3 m C# c, `9 B6 t# w* Q
- name: Restart a container
. A& ]: c$ T+ f) Q9 a% ~; x docker_container:
' s7 v! H3 I) M5 O$ S$ b name: myapplication, Y4 A* x' f% A; U
image: someuser/appimage
! e2 c" k, Q! T3 N( `8 w# u state: started
# Y$ d0 x, f, ?: e) i restart: yes0 [$ j; z- B$ ?) ^6 k+ a# P) V% m
devices:
: U2 o$ \. O" K6 A- L( u4 E - "/dev/sda:/dev/xvda:rwm" w4 m" O( e5 b
ports:$ L, O( ?( l9 W5 u S; u: w) v% ~8 A
- "8080:9000"9 e. w$ B( J7 d+ @! \* C
- "127.0.0.1:8081:9001/udp"
7 ^. F- I% _8 q. a8 n9 c env:+ P$ T( I7 S# I/ E c
SECRET_KEY: "ssssh"8 y6 f8 a( {0 _6 q% y8 I
BOOLEAN_KEY: "yes") q `3 h8 F- c8 Q/ U- w* \
3 无Dockerfile启动镜像并连接容器
! v; r7 r% w5 j在上面的playbook中明确使用了Dockerfile来构建镜像并启动镜像提供服务,但因为Dockerfile自身也是基于基础镜像构建的,所以可以省略这个构建过程,而是直接启动基础镜像并连接到启动的容器进行操作。1 g& w* m5 a+ Z+ d6 W1 q. ?" v
下面实现与上述示例相同的效果,只是不使用Dockerfile构建。 X$ R$ ]+ T1 n+ p( Q
playbook文件内容如下:
; b1 r; K4 J$ }/ h4 x$ F6 i7 ZYaml
+ p5 n0 A0 _: e# [. | Y2 \2 _- y7 @# Y+ } o
---
' g0 g( u5 U' {5 U- name: start image
# U- d" c4 q/ c9 g' S8 O& E4 ] hosts: docker/ ~9 N: G' \: e, h4 L1 i$ X
gather_facts: no
, {5 _' K0 }7 P vars: 4 a, m& ?! T& \
container_name: "centos7"( \6 n% v2 h/ r) z: Q+ E& N9 Z
tasks:
0 e& L# o- {. T% R9 k; B j - name: start basic container "centos7"
9 {& }8 z8 P. Y docker_container: , R( e4 U8 W% q3 d7 d7 `
name: "{{container_name}}"
+ `" I4 `0 V" B1 v V; l hostname: "{{container_name}}" m& `' Z( [% c* N
image: centos:centos7
7 ?$ ?. l2 ~8 ?* L. T( Z+ E% h: @ ports: 8080:80
5 H+ |/ W# R8 z' R- R state: started! z5 e, X. z% o/ Y- I1 p
auto_remove: yes
8 ?8 E6 h! \0 Q# I command: bash
+ v! ~$ \/ _! {: d/ l tty: yes
* i7 W* z7 }" [" O0 x5 v , j0 T* D8 s- q `) @) v) e7 a% q
- name: add container to inventory
; ?' C3 N T2 [* q) O- q add_host: / h( D; Z' P* v. ~
name: "{{container_name}}"
; d$ t: o& U: `* \! f ansible_connection: docker2 S# [' L) t' ~+ a, [/ s6 H
ansible_host: "{{container_name}}"
. C( i t( M; U ansible_user: root( G5 O9 n) s: U: m
groups: containers
. x# p* f# y) x* e
4 i, g {+ X/ ^/ [7 J' }- name: do something in container
: y0 w) f1 C1 T hosts: containers
/ `$ @9 J$ M1 p: x' o; t% O gather_facts: no" y: N4 Q7 o/ C8 g
tasks:
* h: z: P& N- }4 }; l - name: install python if needed( d" [( ?2 Y( o: A: F3 I
raw: yum install -y python
( w! Z+ ?6 C" ` - name: remove all repos exists
c' T- }" |. p7 J. L- F9 F6 Q _ shell: rm -rf /etc/yum.repos.d/*
) ^1 |1 L0 u& I8 o( c 8 f& g6 I: S3 {, T4 [
- name: add os repo and epel repo
7 R: |' Q" E$ P yum_repository: & h2 ]) F x6 v. O2 x3 U3 G3 F! P
name: "{{item.name}}": Z% Y( u8 |4 X, Q
description: "{{item.name}} repo": @0 h9 k1 |, g" W% X! B
baseurl: "{{item.baseurl}}"
( b& k) {* }# x) [) u file: "{{item.name}}" b, Q ?& ?" g/ S# W; D; C+ E' |
enabled: 1( k: }; `" Q6 B/ |8 _
gpgcheck: 01 `- y' c! `, d% D- S" J
reposdir: /etc/yum.repos.d. Z' e% N. }& O8 J
loop:" M# e- _; r, z) q/ @2 z
- name: os% _# \, u( A, D4 Y
baseurl: "https://mirrors.163.com/centos/$releasever/os/$basearch"3 B# C2 Y0 r. c8 y. L6 l
- name: epel/ n/ l1 X# X5 Y; F
baseurl: "https://mirrors.163.com/epel/$releasever/$basearch"
1 c1 g' ]* ^8 v* o# d& M - name: install nginx and cowsay
4 H, P+ p1 i& |: c- k shell: yum -y install nginx cowsay7 V# A- R4 q/ x* L: X, z
4 |/ }% }* L7 K" m2 \1 {
- name: configure nginx
$ K4 \5 u& X6 B& T- t8 } lineinfile: 2 }8 x& r- t- D7 Y( j
line: "daemon off;"
2 h7 ]3 \' Y; c& B6 Q8 U- A# g w dest: /etc/nginx/nginx.conf, Q d- n. H) y1 e- {3 p: g
" p% ^3 i( ]& D V0 V - name: change index page: F) D) W. T; `4 M8 P5 ]/ q: k7 b
block:
+ ^1 \5 b) l: ]) V8 F0 m4 L. q # 先移除index.html,因为它可能是一个软链接
/ O3 v. E T3 X1 P - name: remove old index.html page; I" U* }3 z% |# ^2 s+ K
shell: |, `6 ]3 p/ z7 N9 T# w
rm -rf /usr/share/nginx/html/index.html
: [8 k" U: Q! F cowsay test >/usr/share/nginx/html/index.html
% S2 H4 O* F# t# T0 j& |7 P - name: run nginx! ?4 v* I, l* P6 C& ]; p
shell: nginx &
' U4 t% `" z7 b! B& h+ d在执行上述playbook之前,需要先在Ansible端导出连接方式docker所在主机的环境变量,比如Ansible连接到远程docker时,使用tcp:
9 n# B; c0 j& g4 }Shell7 f+ k6 m( I& Z& w# v3 k
- A x% N" j* K" e
6 n: q) Q7 s1 ^: F( w$ export DOCKER_HOST=tcp://192.168.8.65:23765 Y/ Y h# z; ^* B: j) P; ^
$ ansible-playbook -i inventoryname playbookname.yaml# F0 C0 B( g1 c# a% _
上面的playbook任务中,首先启动docker容器,然后使用了connection: docker连接器添加该容器到containers主机组中,以便后续的连接。之后在第二个play中连接到containers组,安装Python(CentOS系统都会带有python),配置yum源,安装Nginx和cowsay,并启动nginx。任务流程比较简单。
6 X! P5 {- N2 Q唯一需要关注的是add_hosts添加容器节点到inventory时指定的docker连接方式,这里不能使用默认的ssh连接方式,因为目标容器不一定开启了ssh服务,也不一定能和外界通信,而使用connection: docker连接方式,Ansible将会先ssh连接到docker服务所在主机,然后通过docker container exec的方式连接到容器内部。
/ U' r# F0 ~/ U" d8 J docker inventory0 x& V5 ], \# U
Ansible为Docker提供了动态inventory的脚本。可下载该脚本:8 g& J# z" l) g+ N7 K5 `; d
Shell$ V1 w9 w$ ?/ o: K
, ~: N& e1 S3 `1 [- |% ^, a6 c3 J% x ]1 p. v! N
wget https://raw.githubusercontent.com/ansible/ansible/stable-2.9/contrib/inventory/docker.py+ Z+ H% r( @" w- O: v3 q
chmod +x docker.py
6 G/ t+ A- L+ q, l3 O; p执行该脚本测试:
2 A3 w% S, I3 l; ~. N4 oShell
' \- J$ p) U2 [2 l, n
2 J |$ t7 f8 `' \0 S2 xDOCKER_HOST=tcp://192.168.8.65:2376 ./docker.py --pretty9 ], a5 z, N7 C# E
或者直接在ansible命令或ansible-playbook命令中使用-i选项指定:, i; \, t6 h3 C& F) U: s
Shell7 }/ Y& y* e% L; p3 O; |9 S
+ Z( a4 @+ X1 Jansible-playbook -i docker.py docker_containers.yml' D" l; n* D& g" W( C
4 其它Ansible容器管理工具" \5 U$ @8 ?- F4 f: l. F
Ansible除了在官方提供了docker相关的模块外,还有一些第三方的工具可用来管理容器。+ Z, _. D8 J+ i
比如ansible-container、ansible-bender、Ansible Operator,它们需要单独安装,对于ansible-container来说,在之前几年比较知名,但是作者现在已经将该项目废弃,据作者本人所说,ansible-bender和Ansible Operator更好。
+ n4 j, ]( c# V' Xansible-bender:, N6 J; [' T" ~. q
简化Ansible Playbook构建容器(注:此容器是符合OCI标准的容器,docker所构建的底层容器也是OCI容器)
" C8 t3 I2 Y& p: h地址:https://github.com/ansible-community/ansible-bender" K9 ~0 o) d2 ^" {' P3 u ~
Ansible Operator:
# G1 S+ B, B1 Y* }是Red Hat Ansible Automation和Red Hat OpenShift团队联合开发的用来将容器部署到K8s上的工具
) s, d6 g- S' z% E地址:https://learn.openshift.com/ansibleop
{, J( X0 s w) g8 j: X5 Ansible管理OpenStack3 _$ B8 x" k- {) p3 ^. j
OpenStack可整合一台或多台物理计算机的资源来按需创建、管理、配置、删除虚拟机(在OpenStack中,虚拟机对应的术语是”计算实例”,但后文都以虚拟机来描述),对OpenStack提供者来说,提高了硬件资源的利用率;对受益用户来说,可按自己的需求申请带有各种性能、各种资源配置的操作系统,比如公有云的模式,就像去网吧上网一样,想上多久、想体验什么配置的主机都按需付费来享用。, I# Y) [( m- S4 @$ i# ?7 E. a
对于OpenStack来说,Ansible几乎是全程参与其发展的,因为从OpenStack很早的版本开始,就已经逐步支持通过Ansible来配置管理OpenStack,而Ansible管理OpenStack相关的模块也随着OpenStack的版本迭代在不断更新。目前为止,Ansible官方提供的关于OpenStack的模块已经有五十多个,下面是Ansible官方目前提供的模块列表信息简介:% @& G% p. g7 Q9 r$ n/ v
Code! u2 Y7 Z8 A' ^# M I
0 P! d2 L( e; ^5 f, Xos_auth – Retrieve an auth token
5 m' c" S6 U3 L; M. Z: B4 k" P2 sos_client_config – Get OpenStack Client config
6 ]. ^9 ^7 U8 Y" J1 [6 _ \! dos_coe_cluster – Add/Remove COE cluster from OpenStack Cloud5 h: T; z* K9 N. Z% l
os_coe_cluster_template – Add/Remove COE cluster template from OpenStack Cloud
5 H' U6 U* y j$ z+ R" B4 Aos_flavor_info – Retrieve information about one or more flavors
' C* u/ q+ n O: y1 E0 Dos_floating_ip – Add/Remove floating IP from an instance
7 V# D( h! n$ e: e" |os_group – Manage OpenStack Identity Groups, E @' R3 m5 o+ G3 _2 ?
os_group_info – Retrieve info about one or more OpenStack groups$ O! \& x+ n7 V4 Y9 e: E' ]' b/ v8 n
os_image – Add/Delete images from OpenStack Cloud h/ B" D# H) U% N$ z
os_image_info – Retrieve information about an image within OpenStack; |( @/ E! x1 @% k
os_ironic – Create/Delete Bare Metal Resources from OpenStack1 `1 k! Q k. O4 R- `1 x
os_ironic_inspect – Explicitly triggers baremetal node introspection in ironic$ y9 Z) {4 x: H& n7 ]
os_ironic_node – Activate/Deactivate Bare Metal Resources from OpenStack" r9 T( j0 _1 R5 V& F
os_keypair – Add/Delete a keypair from OpenStack# r; T& U# u. v% h' D: P7 n
os_keystone_domain – Manage OpenStack Identity Domains! e8 J v; z% a
os_keystone_domain_info – Retrieve information about one or more OpenStack domains
6 X: O- l# [* ]) uos_keystone_endpoint – Manage OpenStack Identity service endpoints; V' v4 I9 v/ X! \7 ]. _
os_keystone_role – Manage OpenStack Identity Roles! A7 a. l) j/ ~3 q! {9 u& C
os_keystone_service – Manage OpenStack Identity services
7 W7 Q' E' V$ Fos_listener – Add/Delete a listener for a load balancer from OpenStack Cloud
/ u; G( O( w) _+ t/ u0 x4 ros_loadbalancer – Add/Delete load balancer from OpenStack Cloud
+ n9 H( l! a( }* [! Tos_member – Add/Delete a member for a pool in load balancer from OpenStack Cloud. r4 J1 P8 p% s z
os_network – Creates/removes networks from OpenStack
) w5 ?- p8 W. V9 x# D0 r' Eos_networks_info – Retrieve information about one or more OpenStack networks
# h2 z4 i( W z% Tos_nova_flavor – Manage OpenStack compute flavors
0 l/ G+ x; b& i0 A# C) r" W! I& \' kos_nova_host_aggregate – Manage OpenStack host aggregates
6 L" H4 [( \! w0 R% l% [7 A5 O; k2 Aos_object – Create or Delete objects and containers from OpenStack) ~4 P S2 ?: H `5 [; {8 I
os_pool – Add/Delete a pool in the load balancing service from OpenStack Cloud
* A* N8 ^9 Y2 o! los_port – Add/Update/Delete ports from an OpenStack cloud
0 X' B$ l6 C/ F! pos_port_info – Retrieve information about ports within OpenStack
7 d0 O1 \7 N% D* L" i/ q. Oos_project – Manage OpenStack Projects
1 F1 s" z$ ?4 w2 ]9 Bos_project_access – Manage OpenStack compute flavors access
9 Y3 w* N* O' D) @$ P8 Yos_project_info – Retrieve information about one or more OpenStack projects
; o8 @+ i @6 B1 r! q* E! B7 Wos_quota – Manage OpenStack Quotas& w" F3 O5 V; Y9 V6 D$ W! F+ e! |
os_recordset – Manage OpenStack DNS recordsets
& k, \/ ]# s, k' Z9 _6 p" t; q* hos_router – Create or delete routers from OpenStack
$ |1 p" t) S, A e" U5 b3 Ios_security_group – Add/Delete security groups from an OpenStack cloud
9 J2 b7 m* E' Wos_security_group_rule – Add/Delete rule from an existing security group5 U5 R7 D' m. ]1 N
os_server – Create/Delete Compute Instances from OpenStack
& {1 Z0 l" T( b5 {1 ros_server_action – Perform actions on Compute Instances from OpenStack' o- \4 t/ L! \' S" ~/ E
os_server_group – Manage OpenStack server groups; [9 T3 k" n8 J3 I4 f9 t! B) M
os_server_info – Retrieve information about one or more compute instances& a0 |5 e$ t' Y* l5 d
os_server_metadata – Add/Update/Delete Metadata in Compute Instances from OpenStack
1 Z+ e7 `6 h3 P: [2 l& sos_server_volume – Attach/Detach Volumes from OpenStack VM’s
6 @3 v, U b7 K5 D! a. Nos_stack – Add/Remove Heat Stack$ [; t3 e) Z N9 P
os_subnet – Add/Remove subnet to an OpenStack network
6 E& d# D( a* `4 _0 [ L- G5 Nos_subnets_info – Retrieve information about one or more OpenStack subnets4 B( V/ w: K! u( u- j+ o
os_user – Manage OpenStack Identity Users& j+ O! m& X' [" U5 ?5 W5 p
os_user_group – Associate OpenStack Identity users and groups
; L k1 c3 t' x* dos_user_info – Retrieve information about one or more OpenStack users$ n2 W4 c6 |% S* g6 J1 l
os_user_role – Associate OpenStack Identity users and roles( J$ Y) a8 {! Y5 Q3 {
os_volume – Create/Delete Cinder Volumes
% Z _. j; _5 H. A& ^. a! U/ B Tos_volume_snapshot – Create/Delete Cinder Volume Snapshots) @8 K9 c3 T) {$ r
os_zone – Manage OpenStack DNS zones
' t/ e) z& X1 H虽然看上去很多,但大致可总结为Ansible可对以下资源做管理:
: {- M7 ^ }9 b(1).计算资源
9 A4 P9 d& N, B+ k/ i(2).镜像管理
6 z2 [# R$ }6 J- }( n(3).账户管理和账户认证5 s$ y9 _4 |* b* ]
(4).网络管理
$ O6 }6 H0 @. }6 A) ?8 s, V(5).对象存储管理$ b# ^/ L# a* n5 n$ u' A. b
(6).块存储管理8 t- g2 I* b9 k+ o
对每种资源的管理可分为四类操作:
2 s& e- }8 U- p3 P1 o) Y(1).获取管理目标的信息+ A+ P4 f' K$ H' c2 }* @6 k. N
(2).添加管理目标
3 Q( G# Q N/ l& p(3).修改管理目标的属性
' S/ O- v4 }$ T# F1 ~$ Z(4).删除管理目标6 K' U' x N' a
即增、删、改、查。
+ _, l) [2 o8 x# |8 r! a" {. l此外,由于OpenStack自身已经跟踪了其创建的每个虚拟机的信息,所以Ansible还可以直接从OpenStack中获取这些虚拟机的信息,比如从OpenStack取得某些虚拟机信息来构建动态inventory,这样就免去了手动提供虚拟机inventory的麻烦。7 q% \% K: u& r" J
本文不会介绍Ansible如何操作OpenStack自身(比如添加网络、上传镜像等),这和管理普通服务做的一些基本操作没任何区别,不同的仅仅只是做不同操作而已。本文会介绍Ansible管理OpenStack虚拟机时最常见的两种场景需求:
" w$ ~& Z: Q# H. \# p& h(1).使用Ansible创建虚拟机,然后像平时管理远程主机一样管理这些虚拟机,最后删除这些虚拟机# `* N9 m( f ^, i4 l6 r) S
(2).从OpenStack生成动态inventory/ Z2 t* D, Q3 `& N: A0 w
14.2.1 创建虚拟机& |' B0 E: u: e3 z4 \9 ]6 |8 z
OpenStack管理虚拟机相关的模块都以os_server开头,目前包括如下6个模块:本文大概只会用到os_server模块) G9 |3 T- e/ a' c; p
Code
% C7 e! B# B, y3 C! t2 M! u B
5 N* J+ p* k" N1 U. _os_server – 创建或删除虚拟机
" _- i7 h4 n. {- a. F% T! w; [os_server_action – 对虚拟机做一些操作,比如虚拟机的关机、开机、重启、暂停、恢复等操作" M5 ?1 g$ m+ s. M6 J+ [5 h
os_server_group – 管理OpenStack虚拟机分组,比如测试环境的虚拟机可属于test组,生成环境的虚拟机可属于prod组
2 e ]* ?7 t* `: L( k: ^2 ?7 Xos_server_info – 检索一或多个虚拟机信息,在Ansible2.9之前,该模块名称为os_server_facts,用于检索虚拟机facts信息
8 A! J" U3 O/ ^" Los_server_metadata – 增、删、改虚拟机的元数据信息,比如设置虚拟机的主机名、虚拟机设备信息,如网卡配置、磁盘路径/dev/sda 4 l$ ^! o) {0 h% V( Y+ w N
os_server_volume – 附加、剥离虚拟机的卷
& N! p; _" S2 U这6个模块都要求先安装好版本高于0.12的openstacksdk包,在CentOS 7中只需执行如下命令即可:+ O% H" A' V+ n) ]4 k5 E7 B
Shell
/ H1 d1 `1 w' S; o' b4 I
, J9 ]8 B' k% Z; C j+ b1 t. ?/ }$ pip3 install openstacksdk5 p; Q) z: @, ]! [+ _+ U
为了让Ansible连接到Controller进行管理,需要添加Controller的inventory信息。假如OpenStack的Controller的IP地址为192.168.8.65,可inventory文件openstack中添加如下内容:
8 ?# R0 V, I8 j0 w! |Undefined
9 l3 W, y ~& R' v- Z. V7 x' ?) R. l( U
[openstack_controller]
# p' S! L8 p+ x4 G: M$ I6 r192.168.8.651 ]1 K% R( I' m# _& }
配置Ansible段和controller的ssh认证互信可自行配置,此处不赘述。# M! l& f+ a- @+ N' D4 {' o
然后就可以编写playbook来创建虚拟机,假如playbook文件名为create_vm.yml,其内容如下:
( a$ H D0 u* ]' |5 { ~9 j# EYaml- S5 z: Z! [2 W) x& p8 a
! ?9 l# E* O$ {, L4 F8 _* ?/ z( L9 Y* R- name: create vm
! v# K1 p `6 J0 B; b7 E3 } hosts: openstack_controller9 P* @$ ]' P: N, Z& F, o, p+ A, ~
gather_facts: no
- \8 }8 V# a5 t- e0 Z3 w$ m2 R tasks:
' T' v4 y! x" Y# |5 L - name: Create a new instance! \$ T, Z2 Q) @* U, y2 {2 Z
os_server:5 s5 {' j$ r' o; k. o9 R2 P( Y" ^' ^
state: present
+ E2 j" w5 s# _$ k9 k auth:
7 F1 H9 W/ ^$ q: i* J auth_url: http://192.168.8.65:5000/v3
0 A$ i$ j5 C9 W username: admin& v! b3 c; y+ X s y
password: admin123
; F7 a- E. ?) E project_name: admin
4 h/ U s! i$ q" e6 k: x project_domain_name: "Default"0 c+ W9 J* b) r8 A$ H
user_domain_name: "Default"
1 s7 h+ I1 C+ A) {0 {3 J, t' }4 [6 r name: vm10 P N* Z4 f( u# n& J
image: "CentOS-7.9-x86_64"- P4 [2 `* A `1 @" x U
key_name: ansible_key: w( U0 p M; v) H- e* m- G9 O
timeout: 200: ]8 X- r* L* }8 r) k5 I
flavor: m1.small7 j; F+ q/ t% k
network: 'ext_net'; p1 d! w7 B; X8 N" m$ n8 p# ]
wait: yes4 n. H3 I+ x- E6 I/ `# s
meta:: @1 r- ]3 H0 k) \1 f) u" Y& s9 X
hostname: test1) `7 @1 v' v, ?7 p- R* }/ U; D
group: test_group6 f; M' \/ V7 Z$ i8 Y# a( y5 h
userdata: |
3 I, p3 p& X# S- f) z- F1 b8 j {%- raw -%}#!/bin/bash
' N' F) l( m4 L7 } cp /home/centos/.ssh/authorized_keys /root/.ssh/+ a% @: C! N/ x* q0 i1 P8 j
{% endraw %}
% j: a2 Y. B0 s8 b) E8 Q6 R% lauth部分是认证相关信息,name1表示创建一个名为vm1的虚拟机,image、key_name、falvor、network都是OpenStack中已经配置好的。这里还同时设置了虚拟机创建出来后的主机名为test1,并加入到了test_group主机组。
: C2 n- E# e5 E因为是CentOS镜像系统,该虚拟机创建出来后,默认登录用户名为”centos”,而且默认不支持root登录,为了后续可以使用root登录,上面使用userdata定义了该虚拟机创建后自定义的操作,即将保存的公钥信息拷贝到/root/.ssh目录下。+ V& {0 q+ ^+ ~' I% a9 T
注意os_server创建虚拟机任务中的一项wait: yes,它是默认选项,表示Ansible会等待虚拟机创建完成才会继续执行下面的任务。
) m6 M$ Y3 o: A. W* K因为所有的模块在连接OpenStack时都需要进行身份认证,为了简化playbook中的认证内容,将上面的auth选项段落的内容保存到OpenStack Controller的~/.config/openstack/clouds.yaml文件中。例如:" ^3 p7 }( E/ a
Yaml3 X) d7 H/ ?: ` ~& T
, g3 B; n2 |! e* B7 b
clouds:
. u4 A8 a7 q$ S+ Y mycloud:
* [' g! C5 u3 p! u6 Y auth:
2 E# E* \6 {- q1 H4 y% V auth_url: http://192.168.8.65:5000/v38 v6 {' b- |% o7 R
username: admin; p: I# O+ |$ M# I4 E
password: admin123
3 Z# w. ?1 n; {/ C# K project_name: admin
. o3 ^% _: ~. Z& m6 I! N project_domain_name: "Default"0 h2 B$ e. M$ @. r9 l. {% d
user_domain_name: "Default") ?4 n3 C8 ^/ c5 i. Q- R
以后在模块选项中就可以省略auth,而使用一个cloud: CLOUDNAME即可:
' u7 _( n" Q+ l; ?Yaml
F/ G7 w& o, B$ a: [' b# S7 H9 e/ N1 e8 U
tasks:
, G8 j4 g. @4 l6 ` L - name: Create a new instance
) m- Y M [5 I6 S( o) i os_server:
% l6 @ N( F* _. G( ? clouds: mycloud5 G" H0 Z$ |. X0 R# j- [
state: present
6 m# K; Z& U0 l; S' j0 m name: vm15 Z/ o; ?6 t. D# X
image: "CentOS-7-x86_64": m- U+ z- o) Q4 h2 t ~0 r9 H+ t
key_name: ansible_key4 e/ @; z' a7 w; Z+ I- S7 d) E
timeout: 2006 A/ b( Y+ h/ `1 s0 U! w4 b6 ^
flavor: m1.small
! a4 a9 f3 u7 `+ @: }2 M2 @; D, u network: 'ext_net'
: w6 q) ~# Y( g5 J% Z- | wait: yes. A% X# `$ f2 M: T" {
meta:: y( N+ I" n- |1 C; s2 A0 U: D
hostname: test1$ M9 |5 M, o% d
group: test_group
; E- ~8 N' G( U3 |但是要注意,将认证信息以明文方式写入文件是不安全的,可以使用Ansible的Valut加密。不过OpenStack的dashboard中也已经提供了一个环境配置文件,可以先按照如图所示的位置下载:9 o# x4 A3 }1 O; d- d
0 g. [& Q# U; }6 r
然后以source的方式执行下载到的admin-openrc.sh脚本文件:5 D0 Y4 b% k0 ]2 q
Shell
, }( g5 `# [) S* k8 T
* z+ N5 |/ A1 t1 O: q! E) d3 V/ bsource admin-openrc.sh$ e3 y* Q: W- X
执行完后,Ansible的OpenStack相关模块执行时,auth和cloud指令都可以省略。
1 m3 m" |& R( w& f. N上面只是创建一个虚拟机实例,但很多时候可能需要一次性创建多个虚拟机。可以将每个虚拟机相关信息定义到一个变量文件中,然后去遍历想要创建的虚拟机实例。例如:
' C& ?+ [ S) ~/ t; V% YCode- @ D. V: E) M4 h2 g1 ]
% y) T8 o' [. X: S" H5 X
---- n- r6 J3 `" U+ K8 T
servers:. n7 u# t: R0 O' H# Z
- name: vm12 r% A+ D- d, F# D! N* u/ c
image:
9 d% K- ~# M8 ?" Y* I& t6 O flavor:
- O- Z5 ^4 v0 P- x key: / [7 ?0 I( f0 a- I5 y, a+ y/ c3 [
nics:
$ B) o0 H8 o% h8 [! \( | meta: 1 A! t; G- [2 l9 e8 }( O+ q& i7 Y
hostname: T6 e$ y/ O6 d$ e* f% Q7 E: c
group: ) _7 T, n. ?, n
- name: vm2
, J& k& K) y; }; h( v' \% S( k image: ' B- \ h! w6 h9 v
flavor: 7 f4 D/ r- d R$ J
key: ! n- _* d: n. n: C
nics: % C( K$ `& D& C, ?- l
meta: , b8 Y8 L# Z" j7 S/ z% r1 ^
hostname: ; [, w" m5 @9 C
group:
+ u, h- Y' {+ ?# I, k7 e. {* n有了前面的Ansible基础后,此处批量创建虚拟机应该毫无难度。
; U: s2 V8 t: o: k8 {- _: r创建虚拟机后,可以将os_server的任务注册到一个变量,从而可以获取该虚拟机的信息,包括该虚拟机的IP地址: ^- I1 P( G$ A" T/ A! @
Yml
# V4 \) s3 y1 N+ \; E( Q
9 K: f4 E, D: x4 C7 ~9 _2 ltasks: 1 V8 n. H7 T# k1 h5 l1 N0 a
- name: Create a new instance8 l8 A# l; N5 w4 a# F3 O0 c
os_server:8 N) B" p4 W% k7 ~/ m2 ~
cloud: mycloud( Z/ ~0 {, K% a. ?/ A2 n( G
state: present
y; N. w3 C7 x7 S8 ^1 p name: vm1
$ P4 @3 M) ^* R1 h image: "CentOS-7.9-x86_64"
% @9 M# p; x/ }2 T$ z- m key_name: ansible_key/ B" ~ S$ k% M9 k
timeout: 2003 K/ V* Y# E2 g+ \- ^9 b2 ]
flavor: m1.small* U7 h+ V! Q: y9 E$ U
network: 'ext_net'9 c) W% h! l' H8 B
wait: yes- I9 @5 K% T2 {6 Z
meta:! l1 z5 g# C. h n) g
hostname: test1
8 ?1 N) c. A$ j; b group: test_group( m4 N4 I; I$ B3 G h* N; I; Z' \
register: newserver
9 [0 {: j8 \) U' } / W$ B; O! a4 f: N- j
- name: get instance ip7 D* [1 P% N; [& ^7 p3 k
debug: 3 F4 ? U7 F8 h
var: newserver.openstack.accessIPv4! g3 z) J/ U' M% A$ `- X1 U
有了IP地址,对Ansible来说就获得了最关键的信息,因为只要将新虚拟机添加到Ansible inventory中,新虚拟机便像普通节点一样可接受Ansible的控制。
6 M9 A: h' Z* c2 e6、将新虚拟机动态添加到inventory
. L8 b( } \+ C获取到IP地址后,可以将该节点通过add_host模块动态加入到inventory中:
( j: h* E4 n8 M, OYaml+ |: u/ j) t4 u+ p0 b9 n1 N0 Z
" ] c) }$ R7 p4 y% Z
- name: add new vm to inventory8 o( ?' ^. {& ?1 C
add_host:
( l* I( h/ i1 z9 c( j$ X/ V) G* \8 R name: "{{ newserver.openstack.accessIPv4 }}"
0 ?! U/ T1 l/ h ansible_host: "{{ newserver.openstack.accessIPv4 }}"
/ o1 L4 P- D, \% d# E# s$ B ansible_user: "centos"
9 f9 o+ i: `+ Q ansible_port: 22
1 Q0 H+ ~ f; K2 _ groups:
) Z6 b0 `( y7 B: [5 | - vm_hosts: i. }& O G7 p* i
似乎这里的逻辑不太良好?如果虚拟机启动了但是不可连接呢?对于OpenStack创建的虚拟机来说,完全不用担心,因为os_server创建虚拟机成功后会等待该虚拟机可连接才真正返回。但对于非OpenStack的其它云主机实例则不一定,这时应当使用wait或wait_for_connection模块定义一个等待任务。尽管OpenStack中可以省略该步骤,但在脑海中应当要知道有这个步骤。
8 o8 K& Q7 j6 D$ }" ]此外,OpenStack安装的镜像系统可能是比较精简的系统,甚至没有安装Python,所以为了能管理这些虚拟主机,应先使用raw模块安装Python。7 Q! F5 b( {5 {4 E
Yaml+ n3 ^% p) s% {6 d# z! s" a( Z
- name: for new vm host2 g4 t4 y1 ?& U5 Q! G1 {% D
hosts: vm_hosts2 c8 d5 `* W, l c: \
gather_facts: no1 K- |/ g8 G) p
tasks:
% v) R/ J J8 `: _ - name: install python if needed
7 G9 f' z2 r( V4 H4 a raw: "sudo yum install -y python"7 Q- ]: ]2 e9 H2 J, b) ?
如此,Ansible便可以像管理普通主机一样管理OpenStack虚拟机。
% ?+ C/ G. U- \/ {9 O3 @; B3 N7、收集OpenStack虚拟机的动态inventory
6 b6 Q. Z0 l- F/ Q9 t6 o+ W动态inventory一般需要写脚本(几乎是Python脚本)来收集,但即使不会Python也不用担心,因为对于OpenStack来说,官方已经提供了openstack插件,还提供了openstack_inventory.py脚本,该脚本位于Ansible官方github仓库的contrib/inventory目录下,查看文件时记得先选择对应Ansible版本的分支。
7 L2 Y2 w& \2 H" c% C# ?. x* L; v下载openstack_inventory.py并设置可执行权限:
/ T- i( v$ \+ ~, a% k/ d6 rShell
* J/ k8 |* q" W6 K2 U: c: l4 u P5 g' L* o
wget https://raw.githubusercontent.com/ansible/ansible/stable-2.9/contrib/inventory/openstack_inventory.py
) r4 V/ o3 b# Nchmod +x openstack_inventory.py+ L. s# k+ q* q. t: j' E
然后source以下admin-openrc.sh脚本,再执行:: _9 j" M+ n/ @/ C" K' N
Shell. N: x5 l) q6 S
# t9 N! R/ [' \- [* ^- d/ ^3 j
source admin-openrc.sh
# c# e! w4 L- X& p./openstack_inventory.py --list
; D$ d& \; D" F: S1 }3 E4 ~5 u可查看inventory信息。9 Q0 p. g! }! ^3 J& H% b4 N
之后要将该脚本在ansible或ansible-playbook中使用,使用-i选项指定即可:
0 Y4 b7 a2 B& Q3 S* HShell
! Q9 Y' c7 f) h: Z! M% z4 f. q1 h$ k4 \* g( B" D
ansible-playbook -i openstack_inventory.py -m ping
9 k% P1 J) W- X/ Z( P1 n7 Y除了使用openstack_inventory.py脚本动态生成inventory外,还可以使用名为”openstack”的inventory插件。要使用openstack inventory插件,首先要在/etc/ansible.cfg中的[inventory]段的enable_plugins中开启script功能:. B5 z! p8 C* `8 x* u; L: d6 n8 x
Shell" g$ q5 b. Y% o4 ]5 X
5 w& q. Y# s9 a2 w) l$ grep 'enable_plugins' /etc/ansible/ansible.cfg ) j$ n3 q8 L* j% b$ J7 f
#enable_plugins = host_list, virtualbox, yaml, constructed
; q4 ~# s# K& M) T3 [! @7 a- E取消上面的注释,加上script:3 B9 p V# \* |& J7 x% _
Ini
6 N8 q( B$ V$ X$ N1 E) Y1 j1 r4 j& O# W% h" [9 r
[inventory]
( D6 n) v, H" `* N, ^! Eenable_plugins = host_list, script, ini, virtualbox, yaml, constructed/ Y3 N% O% b1 z& D
以后只需在yml文件中加上如下plugin指令即可:
) x/ c R# S! @- `; k6 e: ICode" }0 ?2 H( j- t/ [) |
4 M7 K7 i2 G) F2 z2 U$ f, T1 _ ?plugin: openstack4 \, r L3 L" b5 d5 y
5 {6 D1 r' L$ _ |
|