第一百三十四天 : Puppet 的使用与进阶

Puppet

基于puppet 可实现自动化重复任务, 快速部署关键性应用以及在本地或云端完成主动管理变更和快速扩展架构规模.
基于master/agent 模型. 基于RPC 的通信, 基于xml 进行数据交换

define : 使用puppet 语言来定义资源的状态
模拟 : 根据资源关系图, puppet 可以模拟部署无损运行测试代码
强制 : 对比客户端主机状态和定义的资源状态是否一致, 自动强制执行
report : 通过puppt API 可以将日志发送到第三方监控工具

puppet 工作模型 :

  • 单机模型 : 手动应用清单
  • master / agent : 基于RPC 的通信, 基于xml 进行数据交换

puppet 常用资源类型

资源抽象的维度, RAL 如何抽象资源的

三个层次 : 资源抽象层, 事物层, 配置语言层

类型 : 具有类似属性的组件, 例如 package, service, file
将资源的属性或状态与其实现方式分离
仅描述资源的目标状态, 也即实现的结果状态, 而不是具体过程

RAL 由 “类型” 和”提供者” (“provider”) 共同实现

puppet 子命令 :

help :

显示帮助

1
puppet help <command>

1
puppet help <command> <action>

apply :

手动控制如何应用清单
`puppet apply [-d | —debug] [-v | —verbose] [-e | —execute] [ —noop ]

describe :

显示资源类型的帮助信息


1
2
3
4
-l : 列出所有的资源类型
-s : 显示指定类型的简要帮助信息
    puppet describe -s Command
-m : 显示指定类型的元参数, 一般与-s 一同使用

资源定义 : 向资源类型的属性赋值来实现, 可称为资源类型的实例化
资源定义所在的文件即为资源清单 manifest

定义资源的语法 :


1
2
3
4
type {"title":
    attribute => value1,
    attribute2 => value2,
}

注意 ; type 必须使用小写字母, title 是一个字符串, 在同一类型中必须唯一

status :

显示server 的状态

agent :

运行客户端程序

master :

作为服务器主机, 用于控制其他的客户端和本机

module :

官方支持的模块

资源类型

  • group :
    创建和管理组
    name : 组名
    gid : 组ID
    ensure : 状态[present | absent]
    system : 是否为用户组 [true | false]
    members : 成员用户

  • user :
    管理用户
    name : 用户名
    uid : UID
    gid : 基于组ID
    groups : 附加组
    comment : 注释
    expiry : 过期时间
    home : 家目录
    shell : 默认shell 类型
    system : 是否为系统用户
    ensure : present | absent
    password : 加密后的密码串

  • package :
    管理软件包
    name : 软件包名
    ensure : [ installed | present | absent]
    source : 程序包来源 [rpm | yum]

  • service
    服务管理
    ensure : [ installed | present | latest | ]
    path : 启动服务的脚本
    name : 服务名称
    enable : 是否开机启动
    restart : 通常用于重定义为 reload
    hasrestart : 有重启命令 [true | false]
    hasstatus : 有状态查询命令

  • file :
    管理文件
    ensure : 文件类型的确认 [file | directory | link | present | absent ]
    path : 文件路径
    source : 源文件
    content : 文件内容
    target : 符号连接的目标文件
    owner : 属主
    group : 属组
    mode : 权限
    atime/ctime/mtime : 时间戳

  • exec :
    执行命令
    cwd : 命令执行的目录
    command : 要运行的程序
    creates : 文件路径不存在即创建
    user/group : 运行命令的用户身份
    onlyif : 此属性指定一个命令, 此命令正常(退出码为0)运行时, 当前command 才会运行
    unless : 此属性指定一个命令, 此命令非正常(退出码为0)运行时, 当前command 才会运行
    refresh : 重新执行当前command 的替代命令
    refreshonly : 仅接收到订阅资源的通知时方才运行

  • cron :
    设置定时任务
    command:要执行的任务;
    ensure:present/absent;
    hour:
    minute:
    monthday:
    month:
    weekday:
    user:添加在哪个用户之上;
    name:cron job的名称;

    
    
    1
    2
    3
    4
    5
    6
    cron{"timesync":
      command => "/usr/sbin/ntpdate 10.1.0.1 &> /dev/null",
      ensure  => present,
      minute  => "*/3",
      user    => "root",
    }
  • notify :
    在日志中追加记录信息
    message : 信息内容
    name : 信息名称

    
    
    1
    2
    3
    4
    notify {"hello"
      message  => 'hello guys'
      name => 'hello message'
    }

资源引用 :

Type[‘title’]

类型的首字母必须大写

资源有特殊属性 :
  • 名称变量 : (namevar) : name 可省略, 此时将由title表示
  • ensure : 定义资源的目标状态
  • 元参数 : metaparameter :
    • 依赖关系 : before | require
    • 通知关系 : 通知相关其他资源进行刷新操作 notify | subscribe

补充 : before 是表明必须在某个操作之前进行, require 是要求在某个操作执行完后进行

定义的时候, 只需要在意的是目标的状态, 不需要在乎目标的过程

变量

数据类型 :

字符型:引号可有可无;但单引号为强引用,双引号为弱引用;
数值型:默认均识别为字符串,仅在数值上下文才以数值对待;
数组:[]中以逗号分隔元素列表;
布尔型值:true, false;
hash:{}中以逗号分隔k/v数据列表; 键为字符型,值为任意puppet支持的类型;{ ‘mon’ => ‘Monday’, ‘tue’ => ‘Tuesday’, };
undef:未赋值型 ;
正则表达式:
(?[ENABLED OPTION]:[PATTERN])
(?-[DISABLED OPTION]:[PATTERN])

OPTIONS:
i:忽略字符大小写;
m:把 ‘.’ 当换行符;
x:忽略[PATTERN]中的空白字符

变量类型:
  • facts:agent向master 传递信息之前收集的信息
    由facter提供;top scope;将主机信息收集并规范化
  • 内建变量:
    master端变量 $servername, $serverip, $serverversion
    agent端变量 $environment, $clientcert(客户端证书), $clientversion
    parser变量 $module_name(当前应用的模块名称)
  • 用户自定义变量:
    $parameter_value
变量的作用范围

作用域 : top scope | node scope | class scope

任何给定的scope 都可以访问它自己的内容, 以及接收来自于其父scope, 节点scope 以及top scope 的内容

如果要访问非当前scope中的变量, 则需要通过完全限制名称进行, 如 $vhostdir = $apache::params::vhostdir
需要注意的是, top scope 的名称为空, 因此, 如若引用其变量, 则需要使用类似$::osfamily 进行
自己作用域的变量是不需要使用完全限制名称解析进行访问

操作符

=~ : 左侧的字符串能够被右侧的字符所匹配
!~ : 左侧的字符串不能被右侧的字符所匹配
in : 左侧的字符串在右侧的列表中能被匹配到

Puppet 中的if 语句

条件判断, 其中CONDITION 可以有各宗


1
2
3
4
5
6
7
8
9
if CONDITIONS {
    ...
}
elsif CONDITIONS{
    ...
}
else {
    ...
}

示例 :


1
2
3
4
5
6
7
8
9
10
11
12
13
14
if $osfamily =~ /(?i-mx:debian)/ {
    $webserver = "apache2"
} else {
    $webserver = "httpd"
}
    package{'$webserver':
    ensure  => installed,
    before  => [ File["httpd.conf"], Service["httpd"] ],
}
file{"httpd.conf":
    path    => "/etc/httpd/conf/httpd.conf",
    source  => "/root/manifests/httpd.conf",
    ensure  => file,
}

Puppet 中的case 语句

使用方法:


1
2
3
4
5
6
7
case CONTROL_EXPRESSION {
    case1: { ... }
    case2: { ... }
    case3: { ... }
    ...
    default: { ... }
}

CONTROL_EXPRESSION:

  1. 变量
  2. 表达式
  3. 有返回值的函数

各case的给定方式:

  1. 直接字串;
  2. 变量
  3. 有返回值的函数
  4. 正则表达式模式;
  5. default

注意:不能使用列表格式;但可以是其它的selecor;
示例 :


1
2
3
4
5
$webserver = $osfamily ? {
    'Redhat' => "httpd",
    /(?i-mx:debian)/ => "apache2",
    default => "httpd",
}

Puppet 的类

类 : puppet 中命名的代码模块, 常用于定义一组通用目标的资源, 可在puppet 全局调用, 类可以被继承, 也可以包含子类


1
2
3
4
5
6
class NAME {
    ...puppet code...
}
class NAME(parameter1, parameter2) {
    ...puppet code...
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class nginx {
    package{"nginx":
        ensure  => installed,
    }

    service{"nginx":
        ensure  => running,
        enable  => true,
        require => Package["nginx"],
    }
}

class nginx::web inherits nginx {
    file{"ngx-web.conf":
        path    => "/etc/nginx/conf.d/ngx-web.conf",
        ensure  => file,
        require => Package["nginx"],
        source  => "/root/manifests/nginx/ngx-web.conf",
    }

    file{"nginx.conf":
        path    => "/etc/nginx/nginx.conf",
        ensure  => file,
        content => template("/root/manifests/nginx.conf.erb"),
        require => Package["nginx"],
    }

    Service["nginx"] {
        subscribe => [ File["ngx-web.conf"], File["nginx.conf"] ],
    }
}
include nginx::web

Puppet 的模块

模块就是一个按约定的, 预定义的结构存放了多个文件或子目录的目录, 目录里的这些文件遵循一定格式的命名规范
puppet 会在配置的路径下查找所需要的模块


1
2
3
4
5
6
7
8
MODULES_NAME:
|-manifests/
|   |_init.pp
|-files/
|-lib/
|-templates/
|-spec/
|_tests/

模块名只能以小写字母开头,可以包含小写字母、数字和下划线;但不能使用”main”和”settings“;

201612051953001
201612051954001


1
2
3
4
5
6
7
8
9
10
manifests/
    init.pp:必须一个类定义,类名称必须与模块名称相同;
files/:静态文件;
    puppet URL:    
        puppet:///modules/MODULE_NAME/FILE_NAME
templates/:
    tempate("MOD_NAME/TEMPLATE_FILE_NAME")
lib/:插件目录,常用于存储自定义的facts以及自定义类型;
spec/:类似于tests目录,存储lib/目录下插件的使用帮助和范例;
tests/:当前模块的使用帮助或使用范例文件;

mariadb模块中的清单文件示例:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class mariadb($datadir="/var/lib/mysql") {
    package{"mariadb-server":
        ensure  => installed,
    }

    file{'$datadir':
        ensure  => directory,
        owner   => mysql,
        group   => mysql,
        require => [ Package["mariadb-server"], Exec["createdir"], ],
    }

    exec{"createdir":
        command => 'mkdir -pv $datadir',
        require => Package["mariadb-server"],
        path => "/bin:/sbin:/usr/bin:/usr/sbin",
    }

    file{"my.cnf":
        path    => "/etc/my.cnf",
        content => template("mariadb/my.cnf.erb"),
        require => Package["mariadb-server"],
        notify  => Service["mariadb"],
    }

    service{"mariadb":
        ensure  => running,
        enable  => true,
        require => [ Exec["createdir"], File['$datadir'], ],
    }
}

第一百三十三天 : tomcat 的初步使用

Tomcat

Java 的三个方向 :

J2SE : Standard Edition 标准版
J2EE : Enterprise Edition 企业版
J2ME : Mobile Edition 移动版

代表性技术 : EJB Java Plugin, Swing, JIT (java 即时编译器)

Java 的体系结构规范 :

  • Java 编程语言
  • Java Class 文件格式
  • Java API
  • Java VM
    • JVM 的核心组件 :
    • Class Loader
    • 执行引擎
  • Java 编程语言的主要特性 :
    • 面向对象的编程, 多线程, 结构化错误处理, 自动垃圾收集, 动态链接, 动态扩展

GC : garbage collector

JVM 的运行时区域 :

  • 方法区 : 线程共享, 用于存储别JVM加载的class 信息, 常量, 静态变量, 方法等, 持久代
  • 堆 : 是JVM 所管理的内在的最大一部分, 格式GC管理的主要区域, 主流的垃圾收集算法基于分代收集
  • Java栈 : 线程私有, 存储线程和自己的局部变量
  • PC 寄存器 : 线程私有的内存空间, 程序的指令指针
  • 本地方法栈 :

    JSP

    将JSP文件放在java虚拟机上运行

    1
    index.jsp --->jasper ---> index.java ---> index.class ---> JVM

Web Container

Serviet Container :

Java Web Server : JWS
开源实现 : Tomcat (使用Java实现)

Tomcat 的组成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<Server>
    <Service>
        <connector/>
        <connector/>
            ...
            <Engine>
            <Host>
                <Context/>
                <Context/>
                ...
            </Host>
            <Host>
                ...
            </Host>
                ...
            </Engine>
     </Service>
</Server>

组件都由”类”实现

  • 顶级组件 : Server
  • 服务组件 : Service
  • 连接器组件 : http, https, ajp
  • 容器类 : Engine, Host, Context
  • 被嵌套组件 : value, logger, realm, loader, manager
  • 集群类组件 : listener, …

安装 :

JDK
  • rpm 安装 : 添加JAVA_HOME 变量
  • 配置/etc/profile.d/java.sh
  • 1
    JAVA_HOME=/usr/java/
  • 1
    export JAVA_HOME
OpenJDK
  • rpm 安装 :
  • 配置/etc/profile.d/java.sh
  • 1
    JAVA_HOME=/usr
Tomcat
  • rpm 安装
  • 1
    yum install tomcat tomcat-admin-webapp tomcat-webapp
  • 二进制包安装:
  • 1
    CATALILNA_BASE=/usr/local/tomcat
  • 1
    PATH=$CATALINA_BASE/bin:$PATH
  • 1
    export CATALINA_BASE PATH
Tomcat 的目录结构
  • bin : 脚本, 及启动时用到的类
  • lib : 类库;
  • conf : 配置文件
  • logs : 日志文件
  • webapps : webapp 默认部署目录
  • work : 工作目录
  • temp : 临时工作目录
Tomcat 的配置文件
  • server.xml : 主配置文件
  • context.xml : 每个webapp都可以有专属的配置文件, 其配置文件存放于WEB-INF目录下,为其他webapp提供默认配置
  • web.xml : 每个webapp只有在被部署后才能被访问, 这些配置文件通常位于webapp应用程序自己的目录下的WEB-INF 目录中, 用于定义其他webapp的默认部署方式
  • tomcat-user.xml : 用户认证账号和密码文件
  • catalina.policy : 当使用-security 选项来启动tomcat 实例时, 会读取此配置文件来实现基于安全策略的运行方式
  • catalina.properties : Java 属性的定义文件, 用于设定类加载路径, 以及一些JVM的调优相关的参数
  • logging.propeties : 日志系统相关的配置
JSP WebAPP 组织结构:
  • : webapps 的根目录
    • index.jsp : 主页
    • WEB-INF/ : 当前webapp的私资源的目录通常存放当前webapp自用的web.xml
    • META-INF/ : 当前的webapp的私资源目录, 通常存放当前webapp自用的context.xml文
    • classes/ : 类文件, 当前webapp的私有类
    • lib/当前webapp的私有类, 但被打包成jar格式
webapp 的归档模式
  • .war : webapp
  • .jar : EJB的类
  • .rar : 资源适配器
  • .ear : 企业级应用程序

部署(deploy) webapp 的相关操作 :

  • deploy : 将webapp的源文件放置于目标目录, 配置tomcat 服务器能够基于context.xml文件中定义的路径来访问此webapp
    • 有两种方式 : 自动部署和手动部署
      • 手动部署 :
    1. 冷部署 : 把webapp复制到指定位置, 而后启动tomcat
    2. 热部署 : 在不停止tomcat的前提下进行的部署 (使用部署工具manager app, ant脚本, tcd)
  • undeploy : 反部署, 停止webapp, 并从tomcat示例上拆除其部署文件和部署名
  • stop : 停止, 不再向用户提供服务
  • start : 启动处于停止状态的webapp
  • redeploy : 重新部署

Tomcat 常用组件

每个组件都是通过特有的类来实现的, 有的组件还不止一种实现方式

  • Server : tomcat示例, 即运行的一个JVM进程, 监听与8005 端口接收”SHUTDOWN”, 各Server 监听的端口不能相同, 因此一个物理机上启动多个Server实例应该使用不同的端口
  • Service : 用于实现将一个或多个connector 关联至一个engine
  • Connector 组件 : 进入tomcat 的请求可分为两类
    • tomcat 作为独立的应用程序服务器 : standalone, 次数,请求来自于浏览器
    • 1
      http, https
    • tomcat 作为应用程序服务器 : 请求来自于前面反代主机
      • httpd : http, https, ajp
      • nginx : http, https
    • 属性 :
      • address : 监听的IP地址
      • maxThreads : 最大并发连接数
      • port : 监听的端口
      • protocol : 连接器使用的协议, HTTP/1.1 AJP/1.3
      • redirecPort : 重定向端口
      • connectionTimeout : 连接的超时时长, 单位为毫秒, 默认为60000ms(60s)
      • enableLookups : 设置关闭
      • acceptCount : 定义等待队列的长度
      • scheme : 映射的协议类型
      • debug : 是否开启调试模式
      • secure : 安全模式
      • clientAuth : 认证客户端证书
      • sslProtocol : 使用ssl协议
  • Engine : Servlet 的一个实例(默认示例为catalina), 其内部可以有一个或多个Host组件来定义站点, 通常需要通过defaultHost的属性定义默认的虚拟主机
  • 属性 :
    • name=
    • defaultHost= 当传递过来的主机名不在虚拟主机列表里的时候, 使用默认虚拟主机返回结果
    • jvmRoute=
  • Host : 位于Engine容器中用于接收请求并进行处理的主机或虚拟主机, 如前面示例中定义
    • name=定义虚拟主机的名称
    • appBase=定义虚拟主机资源文件所存放的路径, 存放的路径可为相对路径和绝对路径, 两个虚拟主机不能在同一个目录下. 将ROOT目录下的文件作为资源文件.
    • autoDeploy=在Tomcat处于运行状态时,将某webapp放置于appBase所定义的目录中时,是否自动将其部署至tomcat
      
      
      1
      2
      3
      <Host name="localhost"  appBase="webapps"
        unpackWARs="true" autoDeploy="true">
      </Host>
  • Context : 用于定义一个url(路径别名类似), 一个Context 定义表示tomcat实例中的一个web应用程序

在这里的docBase 是jsp文件所在路径, 不是项目文件夹所在路径,
不需要放置或创建ROOT目录, 放在baseDoc 定义的目录下就能读取

补充 : Context 的目录结构


1
2
3
4
5
6
- path
  |- lib
  |- classes
  |- WEB-INF
  |- MATE-INF
  |_ index.jsp

1
2
 <Context path="/bbs" docBase="/webapp/test3"
          reloadable="true">

每一个context 定义也可以使用一个单独的xml文件进行, 其文件的目录为$CATALINA_HOMA/conf/Engine/Host

  • valve 组件 : 访问日志和访问控制功能
    • 示例 :

1
2
3
Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
                prefix="localhost_access_log" suffix=".txt"
                pattern="%h %l %u %t &amp;quot;%r&amp;quot; %s %b" />
    • className : 定义日志的类型
    • directory : 日志所在目录
    • prefix : 日志文件名
    • suffix : 日志后缀名

Tomcat的非独立模式运行

动静分离机制, 把Tomcat 直接响应来自浏览器的请求使用httpd或nginx 进行反代

LNMT :

客户端发出的请求发送到 http服务器, http服务器由nginx 承担, 将用户请求的动态内容反代至tomcat.

  1. 首先, 安装nginx和Tomcat, 正好手上有现成的装好nginx的虚拟机, 我就直接拿来用了
  2. 修改nginx 配置项, 将http请求全部代理至后端Tomcat 主机.
    
    
    1
    2
    3
    4
    5
    location / {
         root   /usr/share/nginx/html;
         proxy_pass http://tc2.nextkara.net:8080/;
         index  index.html index.htm;
    }
  3. 修改修改配置后启动Tomcat 和nginx

结果如图所示
桌面1图

补充 : 进行模式匹配时, proxy_pass 后定义的后端主机的URL最后不能加/ , 加了则为语法错误

对于, 将动态请求和静态文件请求分离


1
2
3
location ~* \.(jsp| do) {
    proxy_pass http://tc.nextkara.net:8080/
}

LAMT

将Tomcat的保持回话的功能转交给Httpd 进行处理, 后端的Tomcat 只进行内容的处理

  1. 安装httpd 和 Tomcat
  2. 修改httpd 的配置文件, 注释掉httpd.conf 文件中的DocumentRoot 项
  3. 新建文件/etc/httpd/conf.d/tomcat.conf 内容如下

    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     <VirtualHost *:80>
             ServerName tc2.nextkara.net
             DocumentRoot "/webapp/tomcat"
             ProxyRequests Off
             ProxyVia On
             ProxyPreserveHost On
             <Proxy *>
                     Require all granted
             </Proxy>
             ProxyPass / http://localhost:8080/
             ProxyPassReverse / http://localhost:8080/
             <Location "/webapp/tomcat">
                     Require all granted
             </Location>
     </Virtualhost>
  4. 启动httpd 和Tomcat , 显示结果如下图
    图2

使用proxy_ajp_module 进行反代

将上述的tomcat.conf 文件中的内容进行修改为如下内容即可完成使用proxy_ajp_module 进行反代的功能
需要在server.xml 中定义connector

1
<connector port="8009" protocol="AJP/1.3" />


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<VirtualHost *:80>
    ServerName tc2.nextkara.net
    DocumentRoot "/webapp/tomcat"
    ProxyRequests Off
    ProxyVia On
    ProxyPreserveHost Off
    <Proxy *>
         Require all granted
     </Proxy>
     ProxyPass / ajp://tc2.nextkara.net:8009
     ProxyPassReverse / ajp://tc2.nextkara.net:8009/
    <Location "/webapp/tomcat">
         Require all granted
     </Location>
</Virtualhost>

后端tomcat 能够根据前端主机传递客户端请求的主机名进行解析到其他不同的虚拟主机上.

Tomcat Cluster

根据需求对主机进行扩展和收缩
Session Cluster : 不适用于集群节点规模较大的场景

实验一 LNAMT

基于nginx 对tomcat 集群进行调度, 每一个tomcat 主机, 使用httpd 服务器对请求进行反代, 然后使用nginx 对服务进行调度, 将会话保存到后端的session cluster 中, 在进行灰度发布时, 不会丢失会话
使用虚拟主机为

  • nginx
  • test-7-1 with tomcat
  • test-7 with tomcat
  • basic 进行访问目标页面