月度归档:2017年11月

从 0 开始使用 Docker 快速搭建 Hadoop 集群环境

Linux

  • Info:
    • Ubuntu 16.10 x64

Docker 本身就是基于 Linux 的,所以首先以我的一台服务器做实验。虽然最后跑 wordcount 已经由于内存不足而崩掉,但是之前的过程还是可以参考的。

连接服务器

  • 使用 ssh 命令连接远程服务器。
ssh root@[Your IP Address]

ssh root@127.0.0.1

更新软件列表

apt-get update

apt-get update
  • 更新完成。

更新完成

安装 Docker

sudo apt-get install docker.io

sudo apt-get install docker.io
  • 当遇到输入是否继续时,输入「Y/y」继续。

Y
  • 安装完成。

安装完成
  • 输入「docker」测试是否安装成功。

docker

拉取镜像

  • 镜像,是 Docker 的核心,可以通过从远程拉取镜像即可配置好我们所需要的环境,我们这次需要的是 Hadoop 集群的镜像。

kiwenlau/hadoop-cluster-docker
  • 在本文中,我们将使用 kiwenlau 的 Hadoop 集群镜像以及其配置。由于我的服务器本身即在国外,因此拉取镜像的速度较快,国内由于众所周知的原因,可以替换为相应的国内源,以加快拉取速度。
sudo docker pull kiwenlau/hadoop:1.0
  • 拉取镜像完成。

sudo docker pull kiwenlau/hadoop:1.0

克隆仓库

  • 克隆仓库到当前文件夹(可以自行创建并切换到相应文件夹)。
git clone https://github.com/kiwenlau/hadoop-cluster-docker
  • 克隆仓库完成。

克隆仓库完成

桥接网络

sudo docker network create --driver=bridge hadoop

sudo docker network create --driver=bridge hadoop

运行容器

cd hadoop-cluster-docker
./start-container.sh
  • 默认是 1 个主节点,2 个从节点,当然也可以根据性能调整为 N 节点,详见文末参考链接。

./start-container.sh

启动 Hadoop

./start-hadoop.sh
  • 在上一步,我们已经运行容器,即可直接运行 Hadoop。启动时长与机器性能有关,也是难为了我这一台 512 MB 内存的服务器。

./start-hadoop.sh

测试 Word Count

./run-wordcount.sh
  • Word Count 是一个测试 Hadoop 的 Shell 脚本,即计算文本中的单词个数。不过由于我的服务器内存不够分配无法完成,所以后续以本机进行测试。

网页管理

  • 我们可以通过网页远程管理 Hadoop:
    • Name Node: [Your IP Address]:50070/
    • Resource Manager: [Your IP Address]:8088/

macOS

  • Info:
    • macOS 10.12.4 beta (16E191a)

下载 & 安装

  • 打开 Docker 官方网站:https://www.docker.com,选择社区版,并下载、安装。Windows 系统用户可以选择 Windows 版本。

Docker CE

macOS or Windows

运行 Docker

  • 打开 Docker。为了简单,我没有改动配置,如需更改,可以在 Preferences 中修改。

Docker is running
  • 我们可以在终端(Terminal)输入「docker」,测试是否安装成功。

docker

拉取镜像 & 克隆仓库 & 桥接网络 & 运行容器 & 启动 Hadoop

  • 同 Linux。

测试 Word Count

./run-wordcount.sh
  • 同 Linux,但这次我们可以运算出结果了。

./run-wordcount.sh

Windows

其实最开始就没有打算放出 Windows 版,倒不是因为觉得 Windows 不好,而是目前手头没有 Windows 的电脑,借用同学的电脑也不是很方便。如果需要安装 Docker,需要 CPU 支持虚拟化,且安装了 64 位 Windows 10 Pro/企业版(需要开启 Hyper-V)。其他版本的 Windows 可以安装 Docker Toolbox。

  • 暂无。

Intellij IDEA

我们的 Hadoop 集群已经在容器里安装完成,而且已经可以运行。相比自己一个个建立虚拟机,这样的确十分方便、快捷。为了便于开发调试,接下来就需要在 Intellij IDEA 下配置开发环境,包管理工具选择 Gradle。Maven 配合 Eclipse 的配置网上已经有很多了,需要的同学可以自行搜索。

Docker 开启 9000 端口映射

  • 由于我们使用的是 kiwenlau 的镜像和开源脚本,虽然加快了配置过程,但是也屏蔽了很多细节。比如在其脚本中只默认开启了 50070 和 8088 的端口映射,我们可以通过 docker ps(注意是在本机,而不是在容器运行该命令)列出所有容器,查看容器映射的端口。
cd hadoop-cluster-docker
vim start-container.sh
  • 切换到脚本文件夹,使用 Vim 编辑 start-container.sh。在图中光标处添加以下内容,保存并退出。
-p 9000:9000 \

映射 9000 端口
  • 重启容器,并查看容器状态,如图即为映射成功。

映射端口成功

开启 Web HDFS 管理*

该步非必须。为了方便在网页端管理,因此开启 Web 端,默认关闭。

which hadoop
cd /usr/local/hadoop/etc/hadoop/
ls

vi core-site.xml
  • 找到 Hadoop 配置文件路径,使用 Vi 编辑,若 Vi 的插入模式(Insert Mode)中,上下左右变成了 ABCD,那么可以使用以下命令即可:cp /etc/vim/vimrc ~/.vimrc 修复。

Hadoop 配置文件
  • 添加以下内容。
<property>
    <name>dfs.webhdfs.enabled</name>
    <value>true</value>
</property>

添加以上内容

启动 Hadoop

  • 同 Linux。

构建依赖

  • 使用 Intellij IDEA 新建一个 Gradle 项目,在 Build.gradle 中加入以下依赖(对应容器 Hadoop 版本)。
compile group: 'org.apache.hadoop', name: 'hadoop-common', version: '2.7.2'
compile group: 'org.apache.hadoop', name: 'hadoop-hdfs', version: '2.7.2'

Demo

import org.apache.commons.io.IOUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.junit.Before;
import org.junit.Test;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.URI;

/**
 * Created by kingcos on 25/03/2017.
 */
public class HDFSOperations {

    FileSystem fileSystem;

    @Before
    public void configure() throws Exception {
        Configuration configuration = new Configuration();
        configuration.set("fs.defaultFS", "hdfs://192.168.1.120:9000");
        fileSystem = FileSystem.get(URI.create("hdfs://192.168.1.120:9000"), configuration, "root");
    }

    @Test
    public void listFiles() throws IOException {
        Path path = new Path("/");
        RemoteIterator<LocatedFileStatus> iterator = fileSystem.listFiles(path, true);

        while (iterator.hasNext()) {
            LocatedFileStatus status = iterator.next();
            System.out.println(status.getPath().getName());
        }
    }

    @Test
    public void rm() throws IOException {
        Path path = new Path("/");
        fileSystem.delete(path, true);
    }

    @Test
    public void mkdir() throws IOException {
        Path path = new Path("/demo");
        fileSystem.mkdirs(path);
    }
}
  • 之后便可以通过 IDEA 直接写代码来测试,这里简单写了几个方法。

总结

  • 在写这篇文章之前,其实我对 Docker 的概念很不了解。但是通过 Learn by do it. 大致知道了其中的概念和原理。我们完全可以构建自己的容器 Dockerfile,来部署生产和开发环境,其强大的可移植性大大缩短配置的过程。
  • 由于个人对 Hadoop 和 Docker 的了解甚少,如有错误,希望指出,我会学习、改正。
  • 如果有时间,我会再折腾一下其他的玩法 :]

来源:http://www.jianshu.com/p/b75f8bc9346d

使用docker搭建hadoop分布式集群

使用docker搭建部署hadoop分布式集群

在网上找了很长时间都没有找到使用docker搭建hadoop分布式集群的文档,没办法,只能自己写一个了。
一:环境准备:
1:首先要有一个Centos7操作系统,可以在虚拟机中安装。
2:在centos7中安装docker,docker的版本为1.8.2
安装步骤如下:
<1>安装制定版本的dockeryum install -y docker-1.8.2-10.el7.centos
<2>安装的时候可能会报错,需要删除这个依赖

这里写图片描述

rpm -e lvm2-7:2.02.105-14.el7.x86_64

启动docker

service docker start

验证安装结果:
这里写图片描述
<3>启动之后执行docker info会看到下面有两行警告信息
这里写图片描述

需要关闭防火墙并重启系统

systemctl stop firewalld
systemctl disable firewalld
注意:执行完上面的命令之后需要重启系统
reboot -h(重启系统)

<4>运行容器可能会报错
这里写图片描述

需要关闭selinux
解决方法:

1:setenforce 0(立刻生效,不需要重启操作系统)
2:修改/etc/selinux/config文件中的SELINUX=disabled ,然后重启系统生效
建议两个步骤都执行,这样可以确保系统重启之后selinux也是关闭状态

3:需要先构建一个hadoop的基础镜像,使用dockerfile文件方式进行构建。
先构建一个具备ssh功能的镜像,方便后期使用。(但是这样对于容器的安全性会有影响)
注意:这个镜像中的root用户的密码是root
Mkdir centos-ssh-root
Cd centos-ssh-root
Vi Dockerfile

# 选择一个已有的os镜像作为基础  
FROM centos 

# 镜像的作者  
MAINTAINER crxy 

# 安装openssh-server和sudo软件包,并且将sshd的UsePAM参数设置成no  
RUN yum install -y openssh-server sudo  
RUN sed -i 's/UsePAM yes/UsePAM no/g' /etc/ssh/sshd_config  
#安装openssh-clients
RUN yum  install -y openssh-clients

# 添加测试用户root,密码root,并且将此用户添加到sudoers里  
RUN echo "root:root" | chpasswd  
RUN echo "root   ALL=(ALL)       ALL" >> /etc/sudoers  
# 下面这两句比较特殊,在centos6上必须要有,否则创建出来的容器sshd不能登录  
RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key  
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key  

# 启动sshd服务并且暴露22端口  
RUN mkdir /var/run/sshd  
EXPOSE 22  
CMD ["/usr/sbin/sshd", "-D"]

构建命令:
docker build -t=”crxy/centos-ssh-root” .

查询刚才构建成功的镜像

这里写图片描述
4:基于这个镜像再构建一个带有jdk的镜像
注意:jdk使用的是1.7版本的
Mkdir centos-ssh-root-jdk
Cd centos-ssh-root-jdk
Cp ../jdk-7u75-linux-x64.tar.gz .
Vi Dockerfile

FROM crxy/centos-ssh-root
ADD jdk-7u75-linux-x64.tar.gz /usr/local/
RUN mv /usr/local/jdk1.7.0_75 /usr/local/jdk1.7
ENV JAVA_HOME /usr/local/jdk1.7
ENV PATH $JAVA_HOME/bin:$PATH

构建命令:
docker build -t=”crxy/centos-ssh-root-jdk” .

查询构建成功的镜像
这里写图片描述

5:基于这个jdk镜像再构建一个带有hadoop的镜像
注意:hadoop使用的是2.4.1版本的。
Mkdir centos-ssh-root-jdk-hadoop
Cd centos-ssh-root-jdk-hadoop
Cp ../hadoop-2.4.1.tar.gz .
Vi Dockerfile

FROM crxy/centos-ssh-root-jdk
ADD hadoop-2.4.1.tar.gz /usr/local
RUN mv /usr/local/hadoop-2.4.1 /usr/local/hadoop
ENV HADOOP_HOME /usr/local/hadoop
ENV PATH $HADOOP_HOME/bin:$PATH

构建命令:
docker build -t=”crxy/centos-ssh-root-jdk-hadoop” .

查询构建成功的镜像
这里写图片描述

二:搭建hadoop分布式集群
1:集群规划
准备搭建一个具有三个节点的集群,一主两从
主节点:hadoop0 ip:192.168.2.10
从节点1:hadoop1 ip:192.168.2.11
从节点2:hadoop2 ip:192.168.2.12

但是由于docker容器重新启动之后ip会发生变化,所以需要我们给docker设置固定ip。使用pipework给docker容器设置固定ip
2:启动三个容器,分别作为hadoop0 hadoop1 hadoop2
在宿主机上执行下面命令,给容器设置主机名和容器的名称,并且在hadoop0中对外开放端口50070 和8088

docker run --name hadoop0 --hostname hadoop0 -d -P -p 50070:50070 -p 8088:8088 crxy/centos-ssh-root-jdk-hadoop

docker run --name hadoop1 --hostname hadoop1 -d -P crxy/centos-ssh-root-jdk-hadoop

docker run --name hadoop2 --hostname hadoop2 -d -P crxy/centos-ssh-root-jdk-hadoop

使用docker ps 查看刚才启动的是三个容器

这里写图片描述

3:给这三台容器设置固定IP
1:下载pipework
下载地址:https://github.com/jpetazzo/pipework.git
2:把下载的zip包上传到宿主机服务器上,解压,改名字

unzip pipework-master.zip
mv pipework-master pipework
cp -rp pipework/pipework /usr/local/bin/ 

3:安装bridge-utils

yum -y install bridge-utils

4:创建网络

brctl addbr br0
ip link set dev br0 up
ip addr add 192.168.2.1/24 dev br0

5:给容器设置固定ip

pipework br0 hadoop0 192.168.2.10/24
pipework br0 hadoop1 192.168.2.11/24
pipework br0 hadoop2 192.168.2.12/24

验证一下,分别ping三个ip,能ping通就说明没问题

这里写图片描述

4:配置hadoop集群
先连接到hadoop0上,
使用命令

docker exec -it hadoop0 /bin/bash

下面的步骤就是hadoop集群的配置过程
1:设置主机名与ip的映射,修改三台容器:vi /etc/hosts
添加下面配置

192.168.2.10    hadoop0
192.168.2.11    hadoop1
192.168.2.12    hadoop2

2:设置ssh免密码登录
在hadoop0上执行下面操作

cd  ~
mkdir .ssh
cd .ssh
ssh-keygen -t rsa(一直按回车即可)
ssh-copy-id -i localhost
ssh-copy-id -i hadoop0
ssh-copy-id -i hadoop1
ssh-copy-id -i hadoop2
在hadoop1上执行下面操作
cd  ~
cd .ssh
ssh-keygen -t rsa(一直按回车即可)
ssh-copy-id -i localhost
ssh-copy-id -i hadoop1
在hadoop2上执行下面操作
cd  ~
cd .ssh
ssh-keygen -t rsa(一直按回车即可)
ssh-copy-id -i localhost
ssh-copy-id -i hadoop2

3:在hadoop0上修改hadoop的配置文件
进入到/usr/local/hadoop/etc/hadoop目录
修改目录下的配置文件core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml
(1)hadoop-env.sh

export JAVA_HOME=/usr/local/jdk1.7

(2)core-site.xml

<configuration>
        <property>
                <name>fs.defaultFS</name>
                <value>hdfs://hadoop0:9000</value>
        </property>
        <property>
                <name>hadoop.tmp.dir</name>
                <value>/usr/local/hadoop/tmp</value>
        </property>
         <property>
                 <name>fs.trash.interval</name>
                 <value>1440</value>
        </property>
</configuration>

(3)hdfs-site.xml

<configuration>
    <property>
        <name>dfs.replication</name>
        <value>1</value>
    </property>
    <property>
        <name>dfs.permissions</name>
        <value>false</value>
    </property>
</configuration>

(4)yarn-site.xml

<configuration>
        <property>
                <name>yarn.nodemanager.aux-services</name>
                <value>mapreduce_shuffle</value>
        </property>
        <property> 
                <name>yarn.log-aggregation-enable</name> 
                <value>true</value> 
        </property>
</configuration>

(5)修改文件名:mv mapred-site.xml.template mapred-site.xml
vi mapred-site.xml

<configuration>
    <property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
    </property>
</configuration>

(6)格式化
进入到/usr/local/hadoop目录下
1、执行格式化命令

bin/hdfs namenode -format
注意:在执行的时候会报错,是因为缺少which命令,安装即可

执行下面命令安装
yum install -y which

看到下面命令说明格式化成功。
这里写图片描述

格式化操作不能重复执行。如果一定要重复格式化,带参数-force即可。
(7)启动伪分布hadoop

命令:sbin/start-all.sh

第一次启动的过程中需要输入yes确认一下。
这里写图片描述

使用jps,检查进程是否正常启动?能看到下面几个进程表示伪分布启动成功

[root@hadoop0 hadoop]# jps
3267 SecondaryNameNode
3003 NameNode
3664 Jps
3397 ResourceManager
3090 DataNode
3487 NodeManager

(8)停止伪分布hadoop

命令:sbin/stop-all.sh

(9)指定nodemanager的地址,修改文件yarn-site.xml

<property>
    <description>The hostname of the RM.</description>
    <name>yarn.resourcemanager.hostname</name>
    <value>hadoop0</value>
  </property>

(10)修改hadoop0中hadoop的一个配置文件etc/hadoop/slaves
删除原来的所有内容,修改为如下

hadoop1
hadoop2

(11)在hadoop0中执行命令

  scp  -rq /usr/local/hadoop   hadoop1:/usr/local
  scp  -rq /usr/local/hadoop   hadoop2:/usr/local

(12)启动hadoop分布式集群服务

执行sbin/start-all.sh

注意:在执行的时候会报错,是因为两个从节点缺少which命令,安装即可

分别在两个从节点执行下面命令安装

yum install -y which

再启动集群(如果集群已启动,需要先停止)

sbin/start-all.sh

(13)验证集群是否正常
首先查看进程:
Hadoop0上需要有这几个进程

[root@hadoop0 hadoop]# jps
4643 Jps
4073 NameNode
4216 SecondaryNameNode
4381 ResourceManager

Hadoop1上需要有这几个进程

[root@hadoop1 hadoop]# jps
715 NodeManager
849 Jps
645 DataNode

Hadoop2上需要有这几个进程

[root@hadoop2 hadoop]# jps
456 NodeManager
589 Jps
388 DataNode

使用程序验证集群服务
创建一个本地文件

vi a.txt
hello you
hello me

上传a.txt到hdfs上

hdfs dfs -put a.txt /

执行wordcount程序

cd /usr/local/hadoop/share/hadoop/mapreduce
hadoop jar hadoop-mapreduce-examples-2.4.1.jar wordcount /a.txt /out

查看程序执行结果
这里写图片描述
这样就说明集群正常了。

通过浏览器访问集群的服务
由于在启动hadoop0这个容器的时候把50070和8088映射到宿主机的对应端口上了

adb9eba7142b        crxy/centos-ssh-root-jdk-hadoop   "/usr/sbin/sshd -D"   About an hour ago   Up About an hour    0.0.0.0:8088->8088/tcp, 0.0.0.0:50070->50070/tcp, 0.0.0.0:32770->22/tcp   hadoop0

所以在这可以直接通过宿主机访问容器中hadoop集群的服务
宿主机的ip为:192.168.1.144

http://192.168.1.144:50070/
http://192.168.1.144:8088/

这里写图片描述

这里写图片描述
三:集群节点重启
停止三个容器,在宿主机上执行下面命令

docker stop hadoop0
docker stop hadoop1
docker stop hadoop2

容器停止之后,之前设置的固定ip也会消失,重新再使用这几个容器的时候还需要重新设置固定ip
先把之前停止的三个容器起来

docker start hadoop0
docker start hadoop1
docker start hadoop2

在宿主机上执行下面命令重新给容器设置固定ip

pipework br0 hadoop0 192.168.2.10/24
pipework br0 hadoop1 192.168.2.11/24
pipework br0 hadoop2 192.168.2.12/24

还需要重新在容器中配置主机名和ip的映射关系,每次都手工写比较麻烦
写一个脚本,runhosts.sh

#!/bin/bash
echo 192.168.2.10       hadoop0 >> /etc/hosts
echo 192.168.2.11       hadoop1 >> /etc/hosts
echo 192.168.2.12       hadoop2 >> /etc/hosts

添加执行权限,chmod +x runhosts.sh
把这个脚本拷贝到所有节点,并且分别执行这个脚本

scp runhosts.sh  hadoop1:~
scp runhosts.sh  hadoop2:~

执行脚本的命令 ./runhosts.sh

查看/etc/hosts文件中是否添加成功
这里写图片描述

注意:有一些docker版本中不会在hosts文件中自动生成下面这些映射,所以我们才在这里手工给容器设置固定ip,并设置主机名和ip的映射关系。

172.17.0.25     hadoop0
172.17.0.25     hadoop0.bridge
172.17.0.26     hadoop1
172.17.0.26     hadoop1.bridge
172.17.0.27     hadoop2
172.17.0.27     hadoop2.bridge

启动hadoop集群

sbin/start-all.sh

**

ansible入门

前言

最近看了一下ansible,挺火的一个配置管理工具,对比老大哥puppet,使用起来要简单一些,并且可以批量执行命令,对比同是python语言编写的saltstack,不需要安装客户端(基于paramiko),也更灵活一些,尤其我们现有的登录方式,通过跳板机加密钥,改造成ansible成本很低,准备学习一下以后在生产上使用。

ansible已被红帽收购,目前出到2.0了,和红帽的朋友聊了一下,这个配合现在大火的openstack(红帽是其代码最大贡献者之一),看来以后会成为自动化运维的一个趋势。

官网地址http://docs.ansible.com/

安装

最简单的epel之后,yum install ansible

也可以用pip的方式

pip install ansible即可

如果像我们一样服务器不能连接公网,需要手动下载一下python模块ecdsa, pycrypto, paramiko, MarkupSafe, jinja2, PyYAML, ansible

目前安装的版本是1.9.4

ansible --version
ansible 1.9.4

入门使用

首先把ssh密钥搞好,这里就不说了,保证master和minion之间不通过密码

定义主机和组:

vim /etc/ansible/hosts  #默认的文件位置,也可执行ansible时手动指定hosts文件,通过-i参数

[test]
10.199.2.45
10.199.2.46

[web]
10.199.2.[42:47]  #=10.199.2.42\43\44\45\46\47
test.case.com  #主机名定义

使用第一个模块:

ansible test -m ping -u sre -s #-m接模块名,因为我们使用的是sre账户登录后通过sudo的方式,-u接用户,-s表示sudo方式执行
ansible test:\!10.199.2.46 -m ping -u sre -s #:\!排除某个主机
ansible 10.199.2.46 -m ping -u sre -s #当然也可以直接接ip而不使用组进行

ansible自带了很多模块

可以通过ansible-doc -l 查看总共有哪些模块,ansible-doc ping 显示某个模块的用法,ansible-doc -s ping 显示某个模块在playbooks中的代码片段

远程执行命令模块:

远程执行命令可能是ansible最常用也是最方便的一个功能,这里举几个例子

1.执行minion操作系统命令

1
ansible test -a 'w' -u sre -s #默认模块command,实现执行远程命令,-a接模块参数

2.minion上执行master上脚本

master先创建脚本1.sh

#!/bin/bash

ls /tmp/
ansible test -m script -a '1.sh' -u sre -s  #script模块相当于scp+shell,将本地脚本在远端minion进行执行

3.minion执行minion上脚本,2.45远端存在minion.sh,2.46不存在

1
ansible test -m shell -a '/tmp/minion.sh' -u sre -s

shell和command模块很类似,看帮助信息了解到command和shell功能基本一致,但shell可以使用环境变量、管道等,功能更强大

copy模块 

ansible test -m copy -a 'src=1.sh dest=/tmp/ owner=root group=root mode=0755' -u sre -s
#将本地1.sh文件传到远端,如第二次执行此命令,如无更新,则远端无更新,有更新,则远端更新

yum模块

ansible test -m yum -a "name=nc state=latest" -u sre -s

cron模块

ansible test -m cron -a "name='test' job='ls /tmp' minute=*/2 hour=3,4,5" -u sre -s
#对端服务器crontab -l
#Ansible: test
*/2 3,4,5 * * * ls /tmp

ansible test -m cron -a "name='test' state=absent" -u sre -s #删除该条cron

service模块

ansible test -m service -a "name=ntpd state=started" -u sre -s     
ansible test -m service -a "name=ntpd state=stopped" -u sre -s

user模块

ansible test -m user -a "name=test123" -u sre -s  #创建用户
ansible test -m user -a "name=test123 state=absent remove=yes" -u sre -s  #删除用户并删除家目录

lineinfile模块

复制代码
#用于文件内的内容处理
ansible ctx-lf -m lineinfile -a "dest=/tmp/sudoers line='appuser  ALL=(ALL)       NOPASSWD:ALL' insertafter=^sre" -u sre -s -i host  #在sudo文件中sre开头之后加入line=的内容,insertafter可以写正则或EOF(结尾),同理还有insertbefore也可以写正则或BOF(开头)
ansible ctx-lf -m lineinfile -a "dest=/tmp/sudoers state=absent regexp=^appuser" -u sre -s -i hosts  #去掉正则匹配的所有行
ansible ctx-lf -m lineinfile -a "dest=/tmp/sudoers regexp=^sre line='#sre  ALL=(ALL)       NOPASSWD:ALL'" -u sre -s -i hosts  #将sre开头的最后匹配的一行前边加上#
#也可以用()形式做替代变更,类似sed
ansible ctx-lf -m lineinfile -a "dest=/tmp/sudoers regexp=^(sre.*)$ line='#\1' backrefs=yes" -u sre -s -i hosts   #\1表示第一个()里的内容,注意这种用法需要backrefs为yes,开启扩展正则匹配
ansible ctx-lf -m lineinfile -a "dest=/tmp/sudoers regexp=^(sre.*)$ line='123123' validate='visudo -cf %s'" -u sre -s -i hosts   #加入validate的验证,比如sudo文件如果改错了,可能影响整个系统的管理,加入验证之后,如果修改的sudo文件格式错误,将不会保存

进阶一下,请看下一篇ansible playbook的基本介绍 http://www.cnblogs.com/caseast/p/5181910.html

来源: https://www.cnblogs.com/caseast/p/5180205.html

 

ansible写一个简单的playbook

前言

实现的功能很简单,就是通过ansible批量完成某个账户sudo权限的开通或关闭

目录结构

├── group_vars #放置各种变量的目录,我这里没用
├── hosts #主机和组配置,默认为/etc/ansible/hosts
├── roles #角色目录,里边可以有多个角色,这里只配置了一个common
│   └── common
│       ├── files #用于目录分发的目录
│       ├── handlers #放置处理程序,如重启某个服务
│       │   └── main.yml
│       ├── tasks #任务列表
│       │   └── main.yml
│       └── templates #放置模板目录,这里未用
└── site.yml #主入口配置,ansible-playbook 执行的第一个参数,也可以叫别的名称

文件内容

hosts

[ctx-lf-web] 
10.199.72.34 
 
[ctx-bj-web] 
10.0.32.34 
 
[ctx-lf-db]  
10.199.134.21 
 
[ctx-bj-db]  
10.0.32.39 
 
[ctx-web:children] #通过这种方式,将lf和bj这2个组的主机都归类为ctx-web中,这样后续site.yml的host绑定ctx-web就可以操作以下两个分组
ctx-lf-web 
ctx-bj-web 
 
[ctx-db:children] 
ctx-lf-db 
ctx-bj-db 
 
[ctx-bj:children] 
ctx-bj-web 
ctx-bj-db 
 
[ctx-lf:children] 
ctx-lf-web 
ctx-lf-db 

site.yml

--- 
- hosts: [ctx-bj, ctx-db] #可以选择多个分组,这个要和hosts中能找到
  remote_user: sre #因为需要通过远端普通用户使用sudo的方式,所以还需要配置sudo
  sudo: yes 
  roles: 
  - common #将hosts和common这个角色绑定,这个common需要在roles目录中存在

roles/common
其中包括很多目录,因为需求很简单,只配置了tasks/main.yml

--- 
# 安装libselinux-python,如果目标机打开了selinux,需要安装这个包才可以执行写的操作
- name: ensure libselinux-python 
  yum: name=libselinux-python state=latest 
  tags: #tags打上一个标签,这样当ansible-playbook执行脚本的时候,如果不加--tags 参数,将会执行所有tasks,如加上--tags 某个tags名,则只会执行打上对应tags的tasks
    - comment_appuser_sudo 
    - add_appuser_sudo  
 
# 注释appuser sudo 
- name: Commented-Out appuser sudo  
  lineinfile: dest=/etc/sudoers state=absent regexp="^(appuser.*)$"  validate="visudo -cf %s" #sudoers中删除以appuser开头的用户,其实更科学应该设置一个vars,把appuser作为一个变量这样更灵活
  tags: 
    - comment_appuser_sudo 
 
# 添加appuser sudo 
- name: Add appuser sudo   
  lineinfile: dest=/etc/sudoers insertafter="^sre" line="appuser  ALL=(ALL)       NOPASSWD:ALL" validate="visudo -cf %s" #在sre开头那行后边加入line的信息
  tags:  
    - add_appuser_sudo 

执行

    ansible-playbook -i hosts site.yml --tags comment_appuser_sudo -f 4 #-f并行处理的个数,默认5个,-i指定hosts文件,后接入口yml文件,注意tags,这里选择了comment...将会执行ensure libselinux-python 和Commented-Out appuser sudo这2个tasks,如不接tags参数,则所有tasks都执行

当然,以上都是多此一举

ansible ctx-bj-web -i hosts -m lineinfile -a "dest=/etc/sudoers state=absent regexp='^(appuser.*)$'  validate='visudo -cf %s'" -u sre -s
其实一条命令就搞定了

如何在Kubernetes(k8s)中暴露服务访问

本文是10月18日Rancher在北京举办的Kubernetes技术沙龙中的分享话题之一,由讲师张智博整理撰写成文稿。

Kubernetes概述

最近的一年,kubernetes的发展如此闪耀,正被越来越多的公司采纳用于生产环境的实践。同时,我们可以在最著名的开发者问答社区StackOverflow上看到k8s的问题数量的增长曲线(2015.5-2016.5),开发者是用脚投票的,从这一点看也无疑证明了k8s的火爆程度。

20161024200813

Kubernetes来源于Google生产环境的实践,社区活跃度很高,在github上的Star数17k+,30k+commits,同时由Google主导CNCF基金会也在强力运作k8s的社区发展,也就在几个月前OpenStack社区宣布全面拥抱k8s,这也宣布了全球第大的开源IAAS云社区已经选择k8s作为容器的唯一解决方案。

谈到k8s,无论怎样的议题怎样的开始,我们都先介绍一个k8s整体架构(如下图所示):

20161024200831

  • etcd 作为配置中心和存储服务,保存了所有组件的定义以及状态,k8s的多个组件之间的互相交互也主要通过etcd;
  • kube-apiserver 提供和外部交互的接口,提供安全机制,大多数接口都是直接读写etcd中的数据;

kube-scheduler 调度器,主要干一件事情,监听etcd中的pod目录变更,然后通过调度算法分配node,最后调用apiserver的bind接口将分配的node和pod进行关联;

kube-controller-manager 承担了master的主要功能,比如和CloudProvider(IaaS)交互,管理node,pod,replication,service,namespace等。

基本机制是监听etcd /registry/events下对应的事件,进行处理;kubelet 主要包含容器管理,镜像管理,Volume管理等;kube-proxy 主要用于实现k8s的service机制。提供一部分SDN功能以及集群内部的智能LoadBalancer。

本文分享的内容主要是在minion节点上的pod和service上,pod是k8s应用的具体实例抽象,而service便是这些抽象的集合。

20161024200837

ClusterIP & NodePort & Loadbalancer

回到本文的主题,在k8s中暴露Service访问(无论内部还是外部),都要经过kube-proxy,比如下图中我们定义一个Service,便可以通过访问Service的80端口转发到Pod的9376端口上。

20161024200845

kube-proxy在转发时主要有两种模式Userspace和Iptables。如下图,左侧是Userspace模式,也是kube-proxy默认的方式,所有的转发都是通过kube-proxy软件实现的;右侧是Iptables模式,所有转发都是通过Iptables内核模块实现,而kube-proxy只负责生成相应的Iptables规则。从效率上看,Iptables会更高一些,但是需要Iptables version >=1.4.11,Iptables模式在k8s1.2版本放出,是否开启使用还需要具体斟酌。

20161024200853

Service本身看,有三种方式来暴露访问:

  • ClusterIP:使用集群内的私有ip —— 这是默认值
  • NodePort:除了使用cluster ip外,也将service的port映射到每个node的一个指定内部port上,映射的每个node的内部port都一样。
  • LoadBalancer:使用一个ClusterIP & NodePort,但是会向cloud provider申请映射到service本身的负载均衡。

LoadBalancer Provider主要有aws、azure、openstack、gce等云平台提供。相关实现可以在k8s的源码中看到,如下图所示:

20161024200905

Ingress

Ingress也是k8s中单独定义的对象(如下图所示),它的作用就是实现对外暴露访问的负载均衡,那么它和Service本身LoadBalancer有哪些区别呢?Ingress支持L4、L7负载均衡,LoadBalancer设计上只支持L4;Ingress基于Pod部署,并将Pod网络设置成external network;Ingress controller支持Nginx、Haproxy、GCE-L7,能够满足企业内部使用。

20161024200914

在实际使用时,Ingress的架构如下图所示:

20161024200921

但是在实际使用中,pod可能会产生漂移,由于Ingress Controller也是基于Pod部署,这样Ingress对外的IP会发生变化。在企业内部都会在防火墙上给Service的访问IP设定规则,而IP变动对这一机制是致命的,因为企业不可能经常手动修改防火墙规则。

那么我们就需要一个VIP功能,同时也要能保证Ingress的HA。我们可以考虑在Ingress Controller基础上增加一个keepalived,可以利用keepalived+haproxy的机制来完成VIP的功能。要实现这一机制,可以参考并改动k8s社区中的contrib-keepalived-vip机制。

20161024200929

除了以上介绍的暴露服务机制,还有Hpcloud-service-loadbalancer ,它实现了支持keepalived+nginx、F5、OpenStack Lbaas这些方式,并且支持L4 & L7负载均衡,但是与k8s社区本身的发展机制并不兼容,所以一直没有被合并到社区中。另外还有 Contrib-service-loadbalancer ,这个是社区内部正在发展的,它的想法更远大,考虑会支持Cross-namespace、 Cross-cluster这种级别的负载均衡,同时也是设计了插件机制,目前支持Haproxy,同样也支持L4 & L7负载均衡。

Rancher K8s中暴露服务访问

Rancher自己实现了一个rancher-ingress-controller,它本质上是包装了k8s-ingress-controller,在真正创建负载均衡器上它会调用Rancher Cattle API来创建Rancher自身的LB。

20161024200938

相关代码也是开源的,https://github.com/rancher/lb-controller,lb-controller在启动时候会指定provider为rancher,对应的实现也可在package provider/rancher中看到。

20161024200946

创建Ingress后,也可在Rancher UI上展现出来。

20161024200952

创建过程,可以看我录制这段视频教程,www.kubernetes.org.cn/335.html

总结

本文写于Rancher 1.2版本行将发布之际,1.2版本开始Rancher会更加偏向支持原生的k8s,更多让用户来选择如何定制自己的k8s,届时服务暴露访问的机制我们也可以根据自身的生产实践来改造它。

 

来源: https://www.kubernetes.org.cn/401.html