Aansible
Ansible
什么是 Ansible
Ansible 是一个简单,强大且无代理的自动化语言。
Ansible 的好处:
简单易读:基于 YAML 文本编写,易于阅读,非专业的开发人员也可以编写。
功能强大:它可以同于管理配置,软件安装,流程自动化
无代理:不需要在客户端安装额外的 agent
跨平台支持:支持 linux,Windows,Unix 和网络设备
Ansible 是如何工作的
Ansible 典型的工作方式是通过一个脚本文件(基于 YAML 格式构建的)去控制远端操作系统按照特定的顺序执行相关任务,我们称这个文件为 playbook。
Ansible 安装
准备两台虚拟机
192.168.200.201 ansinle1
192.168.200.205 ansinle2
安装 ansible
###安装epel仓库 yum install epel-release -y ###安装ansuble yum install -y ansible ###查看ansible版本 [root@ansible1 ~]# ansible --version ansible 2.9.27 config file = /etc/ansible/ansible.cfg configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python2.7/site-packages/ansible executable location = /usr/bin/ansible python version = 2.7.5 (default, Apr 11 2018, 07:36:10) [GCC 4.8.5 20150623 (Red Hat 4.8.5-28)]
免密配置
anisble-01上生成密钥对ssh-keygen -t rsa,把公钥放到anisble-02上,设置密钥认证。
[root@ansible1 ~]# ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Created directory '/root/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /root/.ssh/id_rsa. Your public key has been saved in /root/.ssh/id_rsa.pub. The key fingerprint is: SHA256:KJdhYE5BxMOkELQYxipKRCIr/UGI0PNfMJWtOHRuyvg root@ansible1 The key's randomart image is: +---[RSA 2048]----+ |%B BX. ..o | |*B=*+.+ o . | |*.ooooo* . | |+. ..oo+= | |+ o++=S | |. .o+ | | . | | E | | | +----[SHA256]-----+ [root@ansible1 ~]# ssh-copy-id 192.168.200.201 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub" The authenticity of host '192.168.200.201 (192.168.200.201)' can't be established. ECDSA key fingerprint is SHA256:9n/1NFgkbXl7WdAcYAQPGFsdlei/hRRysuaneWzaoRE. ECDSA key fingerprint is MD5:c8:6d:e9:25:d3:c0:25:ad:b1:a2:20:ba:ed:88:8d:09. Are you sure you want to continue connecting (yes/no)? yes /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys root@192.168.200.201's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh '192.168.200.201'" and check to make sure that only the key(s) you wanted were added. [root@ansible1 ~]# ssh-copy-id 192.168.200.205 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub" The authenticity of host '192.168.200.205 (192.168.200.205)' can't be established. ECDSA key fingerprint is SHA256:9n/1NFgkbXl7WdAcYAQPGFsdlei/hRRysuaneWzaoRE. ECDSA key fingerprint is MD5:c8:6d:e9:25:d3:c0:25:ad:b1:a2:20:ba:ed:88:8d:09. Are you sure you want to continue connecting (yes/no)? yes /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys root@192.168.200.205's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh '192.168.200.205'" and check to make sure that only the key(s) you wanted were added.
主机组设置
[root@ansible1 ~]# grep ^[^#] /etc/ansible/hosts [gezi] 192.168.200.205 192.168.200.201
ansible 常用模块
测试连通性
[root@ansible1 ~]# ansible gezi -m ping 192.168.200.205 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong" } 192.168.200.201 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "ping": "pong"
这样就可以批量执行命令了。这里的“gezi”为主机组名,-m后边是模块名字,-a后面是命令。当然我们也可以直接写一个IP,针对某一台机器来执行命令。
[root@ansible1 ~]# ansible gezi -m command -a "hostname" 192.168.200.201 | CHANGED | rc=0 >> ansible1 192.168.200.205 | CHANGED | rc=0 >> ansible2 [root@ansible1 ~]# ansible 192.168.200.201 -m command -a "hostname" 192.168.200.201 | CHANGED | rc=0 >> ansible1
command 模块
[root@ansible1 ~]# ansible gezi -m command -a 'ss -ntl' 192.168.200.205 | CHANGED | rc=0 >> State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 *:22 *:* LISTEN 0 100 127.0.0.1:25 *:* LISTEN 0 128 :::22 :::* LISTEN 0 100 ::1:25 :::* 192.168.200.201 | CHANGED | rc=0 >> State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 *:22 *:* LISTEN 0 100 127.0.0.1:25 *:* LISTEN 0 128 :::22 :::* LISTEN 0 100 ::1:25 :::*
chdir # 在执行命令之前,先切换到该目录
executable # 切换shell来执行命令,需要使用命令的绝对路径
free_form # 要执行的Linux指令,一般使用Ansible的-a参数代替。
creates # 一个文件名,当这个文件存在,则该命令不执行,可以用来做判断
removes # 一个文件名,这个文件不存在,则该命令不执行
copy 模块
源目录会放到目标目录下面去,如果目标指定的目录不存在,它会自动创建。如果拷贝的是文件,如果dest指定的名字和源不同,并且它不是已经存在的目录,相当于拷贝过去后又重命名。但相反,如果dest是目标机器上已经存在的目录,则会直接把文件拷贝到该目录下面。
[root@ansible1 ~]# ansible gezi -m copy -a "src=/etc/passwd dest=/tmp/123" 192.168.200.205 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "checksum": "f8bfb8bffc9b65bcdb742b0382d602dc53182fa5", "dest": "/tmp/123", "gid": 0, "group": "root", "mode": "0644", "owner": "root", "path": "/tmp/123", "secontext": "unconfined_u:object_r:admin_home_t:s0", "size": 846, "state": "file", "uid": 0 } 192.168.200.201 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "checksum": "f8bfb8bffc9b65bcdb742b0382d602dc53182fa5", "dest": "/tmp/123", "gid": 0, "group": "root", "md5sum": "4022cc06f1f2fa60d0eecb807417c1c4", "mode": "0644", "owner": "root", "secontext": "unconfined_u:object_r:admin_home_t:s0", "size": 846, "src": "/root/.ansible/tmp/ansible-tmp-1651907523.71-2541-116257585948476/source", "state": "file", "uid": 0 }
yum 模块
使用Yum模块安装httpd服务 [root@ansible1 ~]# ansible 192.168.200.205 -m yum -a "name=httpd" 192.168.200.205 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "changes": { "installed": [ "httpd" ] }, "msg": "", "rc": 0, "results": [ "Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.163.com\n * extras: mirrors.163.com\n * updates: mirrors.nju.edu.cn\nResolving Dependencies\n--> Running transaction check\n---> Package httpd.x86_64 0:2.4.6-97.el7.centos.5 will be installed\n--> Processing Dependency: httpd-tools = 2.4.6-97.el7.centos.5 for package: httpd-2.4.6-97.el7.centos.5.x86_64\n--> Processing Dependency: /etc/mime.types for package: httpd-2.4.6-97.el7.centos.5.x86_64\n--> Processing Dependency: libaprutil-1.so.0()(64bit) for package: httpd-2.4.6-97.el7.centos.5.x86_64\n--> Processing Dependency: libapr-1.so.0()(64bit) for package: httpd-2.4.6-97.el7.centos.5.x86_64\n--> Running transaction check\n---> Package apr.x86_64 0:1.4.8-7.el7 will be installed\n---> Package apr-util.x86_64 0:1.5.2-6.el7 will be installed\n---> Package httpd-tools.x86_64 0:2.4.6-97.el7.centos.5 will be installed\n---> Package mailcap.noarch 0:2.1.41-2.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n httpd x86_64 2.4.6-97.el7.centos.5 updates 2.7 M\nInstalling for dependencies:\n apr x86_64 1.4.8-7.el7 base 104 k\n apr-util x86_64 1.5.2-6.el7 base 92 k\n httpd-tools x86_64 2.4.6-97.el7.centos.5 updates 94 k\n mailcap noarch 2.1.41-2.el7 base 31 k\n\nTransaction Summary\n================================================================================\nInstall 1 Package (+4 Dependent packages)\n\nTotal download size: 3.0 M\nInstalled size: 10 M\nDownloading packages:\n--------------------------------------------------------------------------------\nTotal 6.2 MB/s | 3.0 MB 00:00 \nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : apr-1.4.8-7.el7.x86_64 1/5 \n Installing : apr-util-1.5.2-6.el7.x86_64 2/5 \n Installing : httpd-tools-2.4.6-97.el7.centos.5.x86_64 3/5 \n Installing : mailcap-2.1.41-2.el7.noarch 4/5 \n Installing : httpd-2.4.6-97.el7.centos.5.x86_64 5/5 \n Verifying : apr-1.4.8-7.el7.x86_64 1/5 \n Verifying : mailcap-2.1.41-2.el7.noarch 2/5 \n Verifying : httpd-tools-2.4.6-97.el7.centos.5.x86_64 3/5 \n Verifying : apr-util-1.5.2-6.el7.x86_64 4/5 \n Verifying : httpd-2.4.6-97.el7.centos.5.x86_64 5/5 \n\nInstalled:\n httpd.x86_64 0:2.4.6-97.el7.centos.5 \n\nDependency Installed:\n apr.x86_64 0:1.4.8-7.el7 apr-util.x86_64 0:1.5.2-6.el7 \n httpd-tools.x86_64 0:2.4.6-97.el7.centos.5 mailcap.noarch 0:2.1.41-2.el7 \n\nComplete!\n" ] }
设置服务状态,这里的name是CentOS系统里的服务名,可以通过chkconfig –list命令查到
[root@ansible1 ~]# ansible 192.168.200.205 -m service -a "name=httpd state=started enabled=yes" 192.168.200.205 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "enabled": true, "name": "httpd", "state": "started", "status": { "ActiveEnterTimestampMonotonic": "0", "ActiveExitTimestampMonotonic": "0", "ActiveState": "inactive", "After": "systemd-journald.socket nss-lookup.target network.target tmp.mount basic.target system.slice remote-fs.target -.mount", "AllowIsolate": "no", "AmbientCapabilities": "0", "AssertResult": "no", "AssertTimestampMonotonic": "0", "Before": "shutdown.target", "BlockIOAccounting": "no", "BlockIOWeight": "18446744073709551615", "CPUAccounting": "no", "CPUQuotaPerSecUSec": "infinity", "CPUSchedulingPolicy": "0", "CPUSchedulingPriority": "0", "CPUSchedulingResetOnFork": "no", "CPUShares": "18446744073709551615", "CanIsolate": "no", "CanReload": "yes", "CanStart": "yes", "CanStop": "yes", "CapabilityBoundingSet": "18446744073709551615", "ConditionResult": "no", "ConditionTimestampMonotonic": "0", "Conflicts": "shutdown.target", "ControlPID": "0", "DefaultDependencies": "yes", "Delegate": "no", "Description": "The Apache HTTP Server", "DevicePolicy": "auto", "Documentation": "man:httpd(8) man:apachectl(8)", "EnvironmentFile": "/etc/sysconfig/httpd (ignore_errors=no)", "ExecMainCode": "0", "ExecMainExitTimestampMonotonic": "0", "ExecMainPID": "0", "ExecMainStartTimestampMonotonic": "0", "ExecMainStatus": "0", "ExecReload": "{ path=/usr/sbin/httpd ; argv[]=/usr/sbin/httpd $OPTIONS -k graceful ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }", "ExecStart": "{ path=/usr/sbin/httpd ; argv[]=/usr/sbin/httpd $OPTIONS -DFOREGROUND ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }", "ExecStop": "{ path=/bin/kill ; argv[]=/bin/kill -WINCH ${MAINPID} ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }", "FailureAction": "none", "FileDescriptorStoreMax": "0", "FragmentPath": "/usr/lib/systemd/system/httpd.service", "GuessMainPID": "yes", "IOScheduling": "0", "Id": "httpd.service", "IgnoreOnIsolate": "no", "IgnoreOnSnapshot": "no", "IgnoreSIGPIPE": "yes", "InactiveEnterTimestampMonotonic": "0", "InactiveExitTimestampMonotonic": "0", "JobTimeoutAction": "none", "JobTimeoutUSec": "0", "KillMode": "control-group", "KillSignal": "18", "LimitAS": "18446744073709551615", "LimitCORE": "18446744073709551615", "LimitCPU": "18446744073709551615", "LimitDATA": "18446744073709551615", "LimitFSIZE": "18446744073709551615", "LimitLOCKS": "18446744073709551615", "LimitMEMLOCK": "65536", "LimitMSGQUEUE": "819200", "LimitNICE": "0", "LimitNOFILE": "4096", "LimitNPROC": "3802", "LimitRSS": "18446744073709551615", "LimitRTPRIO": "0", "LimitRTTIME": "18446744073709551615", "LimitSIGPENDING": "3802", "LimitSTACK": "18446744073709551615", "LoadState": "loaded", "MainPID": "0", "MemoryAccounting": "no", "MemoryCurrent": "18446744073709551615", "MemoryLimit": "18446744073709551615", "MountFlags": "0", "Names": "httpd.service", "NeedDaemonReload": "no", "Nice": "0", "NoNewPrivileges": "no", "NonBlocking": "no", "NotifyAccess": "main", "OOMScoreAdjust": "0", "OnFailureJobMode": "replace", "PermissionsStartOnly": "no", "PrivateDevices": "no", "PrivateNetwork": "no", "PrivateTmp": "yes", "ProtectHome": "no", "ProtectSystem": "no", "RefuseManualStart": "no", "RefuseManualStop": "no", "RemainAfterExit": "no", "Requires": "basic.target -.mount", "RequiresMountsFor": "/var/tmp", "Restart": "no", "RestartUSec": "100ms", "Result": "success", "RootDirectoryStartOnly": "no", "RuntimeDirectoryMode": "0755", "SameProcessGroup": "no", "SecureBits": "0", "SendSIGHUP": "no", "SendSIGKILL": "yes", "Slice": "system.slice", "StandardError": "inherit", "StandardInput": "null", "StandardOutput": "journal", "StartLimitAction": "none", "StartLimitBurst": "5", "StartLimitInterval": "10000000", "StartupBlockIOWeight": "18446744073709551615", "StartupCPUShares": "18446744073709551615", "StatusErrno": "0", "StopWhenUnneeded": "no", "SubState": "dead", "SyslogLevelPrefix": "yes", "SyslogPriority": "30", "SystemCallErrorNumber": "0", "TTYReset": "no", "TTYVHangup": "no", "TTYVTDisallocate": "no", "TasksAccounting": "no", "TasksCurrent": "18446744073709551615", "TasksMax": "18446744073709551615", "TimeoutStartUSec": "1min 30s", "TimeoutStopUSec": "1min 30s", "TimerSlackNSec": "50000", "Transient": "no", "Type": "notify", "UMask": "0022", "UnitFilePreset": "disabled", "UnitFileState": "disabled", "Wants": "system.slice", "WatchdogTimestampMonotonic": "0", "WatchdogUSec": "0" } }
Ansible文档的使用
# ansible-doc -l //列出所有模块 # ansible-doc yum //查看指定模块的文档

浙公网安备 33010602011771号