专栏首页运维博客03 实战 Ansible-Playbook之初始化服务器

03 实战 Ansible-Playbook之初始化服务器

批量初始化服务器

初始化步骤

  • 配置ssh密钥认证
  • 远程配置主机名
  • 控制远程主机互相添加HOSTS解析
  • 配置远程主机的yum源以及一些软件
  • 时间同步配置
  • 关闭selinux/iptables
  • 修改sshd配置

配置ssh密钥认证

  • 在主控节点的/etc/ansible/hosts配置节点
$ vim /etc/ansible/hosts
[new]
192.168.56.12
192.168.56.13

在控制节点配置到受控节点的ssh认证方式

# 主控节点执行
$ ssh-keygen -t rsa -f ~/.ssh/id_rsa -N ''
$ for host in 192.168.56.{11..12};do
ssh-keyscan $host >> ~/.ssh/hnow_hosts 2> /dev/null
sshpass -p '123456' ssh-copy-id root@$host &> /dev/null
done

将上面的方案playbook化:

---
- name: config ssh connection
  hosts: new
  gather_facts: false
  tasks:
    - name: configure ssh connection
      shell: |
          ssh-keyscan {{inventory_hostname}} >> ~/.ssh/know_hosts
          sshpass -p '123456' ssh-copy-id root@{{inventory_hostname}} 

ansible命令执行模块

以下的四个模块不满足幂等性

  • command:执行简单的shell命令
  • shell: 和command相同,但支持管道富豪
  • raw: 执行底层shell命令,通常在目标主机上安装python时才使用这个模块
  • script: 在远程主机上执行脚本

以下命令具备幂等性:

  • creates: 当指定的文件或者目录不存在时执行,存在不执行
  • removes:当指定的文件或者目录不存在时不执行,存在执行
---
- name: modules use
  hosts: new
  gather_facts: false
  tasks:
      - name: use shell module
        shell: cp /tmp/my.cnf /etc/my.cnf
        args:
          creates: /etc/my.cnf
      - name: exec perl scripts
         script: /opt/script.pl
         args:
           executable: perl

重点

  • connection: 连接方式(smart|ssh|paramiko|local|docker|winrm),默认为smart表示只能选择ssh或者paramiko
  • delegate_to: 只能定义在task级别上,效果和connection相似
---
- name: play1
  hosts: zabbix
  gather_facts: false
  tasks:
    - name: task 1
      debug:
        msg: "{{ inventory_hostname }} is executing task"
      delegate_to: localhost

authorized_key模块

特点:

  • 分发ssh公钥
  • 不负责主机认证阶段 前提需要配置好hosts下的ansible_passwd字段 [new] 192.168.56.11 ansible_hostname="centos7-node1" 192.168.56.12 ansible_hostname="centos7-node2" [new:vars] ansible_password="yeecallk8s" 分发认证配置
---
- name: "configure ssh connection"
  hosts: new
  gather_facts: false
  tasks:
    - authorized_key:
        key: "{{lookup('file','~/.ssh/id_rsa.pub')}}"
        state: present
        user: root

外部数据读取的方式:

  • lookup() :支持从file,redis,etcd,pipe,vars,list,dict
    • fileglob: 支持统配文件名,file指定文件,pipe从命令执行结果中返回数据
---
- name: "fileglob and file task"
  hosts: new
  gather_facts: false
  tasks:
    - name: task1
      debug:
        msg: "filenames: {{ lookup('fileglob','/etc/*.conf')}}"
    - name: task2
      debug:
        msg: "filecontents: {{ lookup('file','/etc/hosts')}}
  • query() : 统配文件读取,返回list格式
---
- name: "fileglob and files query"
  hosts: new
  gather_facts: false
  tasks:
    - name: "fileglob"
      debug:
        msg: "fileglob {{lookup('fileglob','/etc/*.conf')}}"
    - name: "fileglob wantlist"
      debug:
        msg: "fileglob wantlist {{lookup('fileglob','/etc/*.conf',wantlist=True)}}"
    - name: "query"
      debug:
        msg: "query {{q('fileglob','/etc/*.conf')}}"

设置主机名

使用的是hostname模块,会直接修改/etc/hostname 配置文件

---
- name: set hostname
  hosts: new
  gather_facts: false
  vars:
    hostnames:
      - host: 192.168.56.13
        name: centos7-node3
      - host: 192.168.56.14
        name: centos7-node4
  tasks:
    - name: set hostname
      hostname:
        name: "{{ item.name }}"
      when: item.host == inventory_hostname
      loop: "{{ hostnames }}"

vars变量设置注意:

  • 设置在play级别,该play范围内的task都能访问这些变量,其他的play则无法访问
  • 设置在task级别,只有该task范围内才能访问这个变量
---
- name: vars task1
  hosts: new
  gather_facts: false
  vars:
    - var1: "value1"
  tasks:
    - name: access value1
      debug:
        msg: "var1 in task1 {{var1}}"

- name: vars task2
  hosts: new
  gather_facts: false
  tasks:
    - name: can not access vars from task1
      debug:
        msg: var1
    - name: set and access var2 in this task
      debug:
        msg: var2
      vars:
        var2: "value2"
    - name: cant access var2
      debug:
        msg: var2

when条件判断

  • 当when判断为true的时候执行任务,反之不执行
---
- name: when judge
  hosts: new
  gather_facts: false
  vars:
    - myname: "alex"
  tasks:
    - name: task skip
      debug:
        msg: "my name is {{myname}}"
      when: myname == "hello"   #这个判断条件是false的
    - name: task will execute
      debug:
        msg: "my name is {{myname}}"
      when: myname == "alex"

loop循环: 解决重复问题

  • 未使用循环的例子
---
- name: make dirs for localhost
  hosts: localhost
  gather_facts: false
  tasks:
    - name: create test1
      file:
        path: /tmp/test1
        state: directory
    - name: create test2
      file:
        path: /tmp/test2
        state: directory
  • 使用循环的例子
---
- name: mkdir loop
  hosts: localhost
  gather_facts: false
  tasks:
    - name: create test1,2 directory
      file:
        path: "{{item}}"
        state: directory
      loop:
        - /tmp/test01
        - /tmp/test02

互相添加hosts(DNS)主机名解析

互相添加指定hosts组的host之间的hosts解析

---
- name: add hosts DNS
  hosts: new
  gather_facts: false
  tasks:
    - name: add DNS
      lineinfile:
        path: /etc/hosts
        line: "{{item}} {{hostvars[item].ansible_hostname}}"
      when: item != inventory_hostname
      loop: "{{ play_hosts }}"
  • lineinfile模块: 在源文件中插入,删除,替换行,跟sed类似
# 创建测试文件a.txt 
paragraph 1
first line in paragraph 1
second line in paragraph 1
paragraph 2
first line in paragraph 2
second line in paragraph 2

## lineinfile追加实例
---
- name: add line to a.txt
  hosts: localhost
  gather_facts: false
  tasks:
    - lineinfile:
        path: "a.txt"
        line: "append new line"
        state: absent     # 删除上面的line定义的行(append new line)

### 插入操作,定义在摸个行前或者行后新增(insertbefore,insertafter)
---
- name: lininfile demo for before and after insert
  hosts: localhost
  gather_facts: false
  tasks:
    - name: line infile
      lineinfile:
        path: "a.txt"
        line: "LINE1"
        insertbefore: '^para.* 2'
        firstmatch: yes
      lineinfile:
        path: "a.txt"
        line: "LINE2"
        insertafter: '^para.* 2'
        firstmatch: yes
  • play_hosts和hostvars变量
    • inventory_hostname: 表示在主机inventory中定义的名称
    • play_hosts和hostvars: 是预定义变量,执行任务时可以直接拿出来使用,play_hosts相当于是new这个主机组里面的所有主机列表;
      • hostvars: 保存了所有目标主机的变量
- name: add DNS
      lineinfile:
        path: /etc/hosts
        line: "{{item}} {{hostvars[item].ansible_hostname}}"
      when: item != inventory_hostname
      loop: "{{ play_hosts }}"

配置yum源并下载安装软件

更换yum源,安装软件

---
- name: "init yum"
  hosts: new
  gather_facts: false
  tasks:
    - name: "backup old yum_repo"
      shell:
        cmd: "mkdir bak; mv *.repo bak"
        chdir: /etc/yum.repos.d
        creates: /etc/yum.repos.d/bak
    - name: "add new os repo and release repo"
      yum_repository:
        name: "{{item.name}}"
        description: "{{item.name}} repo"
        baseurl: "{{item.baseurl}}"
        file: "{{item.name}}"
        enabled: 1
        gpgcheck: 0
        reposdir: /etc/yum.repos.d
      loop:
        - name: os
          baseurl: "https://mirrors.tuna.tsinghua.edu.cn/centos/$releasever/os/$basearch"
        - name: epel
          baseurl: "https://mirrors.tuna.tsinghua.edu.cn/epel/$releasever/$basearch"
    - name: install pkgs
      yum:
        name: vim,net-tools,git-core,lrzsz,wget,curl,sysstat,iotop,gcc,gcc-c++,cmake,pcre,pcre-devel,zlib,zlib-devel,openssl,openssl-devel,vim,wget,telnet,setuptool,lrzsz,dos2unix,
net-tools,bind-utils,tree,screen,iftop,ntpdate,tree,lsof,iftop,iotop,sysstat,procps
        state: present

时间同步

使用ntpdate 同步时间

 ---
- name: sync time
  hosts: new
  gather_facts: false
  tasks:
    - name: install and sync time
      block:
        - name: install ntpdate
          yum:
            name: ntpdate
            state: present
        - name: ntpupdate to sync time
          shell: |
            ntpdate ntp1.aliyun.com
            hwclock -w
  • block是组织了两个有关联性的任务

关闭selinux

命令行关闭和修改配置文件两种手段

---
---
- name: disable selinux
  hosts: new
  gather_facts: false
  tasks:
    - block:
        - name: disable selinux by command
          shell: setenforce 0

        - name: disable selinux by config
          lineinfile:
            path: /etc/selinux/config
            line: "SELINUX=disabled"
            regexp: '^SELINUX='
      ignore_errors: true

配置防火墙

---
- name: set firewalld
  hosts: new
  gather_facts: false
  tasks:
    - name: set iptables rule
      shell: |
        iptables-save > /tmp/iptables.bak$(date +"%F-%T")
        iptables -X
        iptables -F
        iptables -Z
        systemctl disable firewalld
        systemctl stop firewalld

配置sshd服务

  • 需求:
    • 禁止root用户登陆
    • 不允许使用密码登陆
---
- name: "set sshd service"
  hosts: new
  gather_facts: false
  tasks:
    - name: backup old sshd config
      shell: |
        /usr/bin/cp -f {{path}} {{path}}.bak
      vars:
        - path: /etc/ssh/sshd_config
    - name: disable root login
      lineinfile:
        path: "/etc/ssh/sshd_config"
        line: "PermitRootLogin no"
        regexpr: '^PermitRootLogin'
      notify: "restart sshd"
    - name: disable passwd auth
      lineinfile:
        path: "/etc/ssh/sshd_config"
        line: "PasswordAuthentication no"
        regexp: '^PasswordAuthentication yes'
      notify: "restart sshd"
  handlers:
    - name: "restart sshd"
      service:
        name: sshd
        state: restarted

参考

推荐专栏:https://blog.51cto.com/cloumn/detail/83from_distribution=VQcJVApVVQwxUwIHVQYFDA 代码gitee:https://gitee.com/wanghui1234/ansible_repo.git

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • CICD(三)Ansible常用模块以及案例

    alexhuiwang
  • kubernetes(十六) k8s 弹性伸缩

    常规的做法是给集群资源预留保障集群可用,通常20%左右。这种方式看似没什么问题,但放到Kubernetes中,就会发现如下2个问题。

    alexhuiwang
  • 02-Ansible入门进阶

    alexhuiwang
  • 万恶之源 - Python基础数据类型一

    在32位机器上int的范围是:  -2**31~2**31-1,即-2147483648~2147483647

    py3study
  • 动手实现一个AMD模块加载器(三)

    在上一篇文章中,我们的AMD模块加载器基本已经能够使用了,但是还不够,因为我们没有允许匿名模块,以及没有依赖等情况。实际上在amd的规范中规定的就是define...

    用户1515472
  • redis python

    现在我们已经在本地安装了Redis并运行在6379端口,密码设置为123。那么,可以用如下示例连接Redis并测试:

    用户6413882
  • Python操作Redis,你要的都在这了!

    崔庆才
  • 网站搭建-django-学习成绩管理-06-数据库操作之ORM-1

    系统:Windows 7 语言版本:Anaconda3-4.3.0.1-Windows-x86_64 编辑器:pycharm-community-2016.3....

    zishendianxia
  • Springmvc响应Ajax请求(@ResponseBody)

    爱撒谎的男孩
  • django 模型中的计算字段实例

    在search_fields中加入一个外键的名字是不能查询的,要写成(外键名__外键中的字段名)的形式.

    砸漏

扫码关注云+社区

领取腾讯云代金券