Linux两块磁盘挂载指向一个文件夹LVM磁盘管理(二)

注意:任何磁盘的操作有可能损坏里面数据,请提前备份数据,切记!切记!切记!

0x00:前言

VG卷组的总空间是受物理磁盘大小限制,本教程有3块物理磁盘分别是100M、200M、300M,那么VG卷组总空间就是600M;而VG下所有的LV累加的总空间又受限于VG。

使用过程中LV早晚会用完,那么上面的/LVM挂载点只能同时挂载一个,而有些程序不能支持有两个文件目录,比如WEB只有一个/,还有MySQL。

0x01:扩展VG卷组、缩小VG卷组

1)扩展VG卷组

上一章讲我看到添加了3块物理磁盘,第一块(/dev/sdb1)已经加入VG组,这次来把第二块(/dev/sdc1)加入到之前的那个vgdata的VG组里。

首先还是格式化磁盘,并创建磁盘分区/dev/sdc1。这里图略,和之前一样。

# fdisk /dev/sdc  //显示创建磁盘并和格式化,略去一些命令

略。

# pvcreate /dev/sdc1   //普通磁盘转换成PV
# pvs  //查看VG组信息
# vgextend vgdata /dev/sdc1   //加入VG组,vgdata要加入VG组名,/dev/sdc1新PV

图里可以看到磁盘第一次pvs里只有一个PV,添加后,第二次pvs就又有多出一块PV。

未分类

# vgdisplay  //查看VG卷组详细信息,VG的总空间已经由之前100M变成300M

未分类

2).缩小卷组

实际使用中,因为磁盘损坏,或空间分配问题,我们需要从VG卷组删除一个PV物理卷。用过的PV物理卷肯定会被写入数据,那么在移走PV前,我们要先迁移数据。

先用pvdisplay命令看看上面PE块被写了多少数据,假如/dev/sdb1是要移走的物理硬盘。

注意,目的地空闲空间要大于/dev/sdb1。

我们准备了/dev/sdd1来存放迁移过来的数据。

未分类

从上图可以看出sdb1总空间是100M,然后空闲是0M,也就是使用了100M。

# pvmove -i 1 /dev/sdb1 /dev/sdd1  //将sdb1数据移动到sdd1里,
                                              -i 1是每1秒钟报告一次数据迁移的进度。
# vgreduce vgdata /dev/sdb1  //将/dev/sdb1从vgdata卷组中移除
#  pvremove /dev/sdb1  //将/dev/sdb1移除出PV

未分类

结果:数据没有任何丢失。

未分类

0x02:扩展LV、缩小LV逻辑卷

1)VG卷组又有新的空间,而刚才创建的lvData(/dev/sdb1)已经使用完了,我们来扩展LV。

# lvextend –L +50M /dev/vgdata/lvData
或者
# lvextend –l 150M /dev/vgdata/lvData

-L和-l区别,-L后是写你要增加多少,而-l是写你要增加到的总数。

执行命令后我们发现LV size变成150M了。

未分类

LV扩容完系统还没有识别,需要用resize2fs来更新,系统才能识别到。

# resize2fs /dev/vgdata/lvData

未分类

2)缩小LV(逻辑卷)空间。

使用过程中LV空间总会分配不合理或大或小,如果分配大了,不用又造成空间浪费,现在将LV(逻辑卷)缩小以分配给其他LV(逻辑卷)用。

我们之前创建了一个LV(逻辑卷),挂载到了/LVM下。

未分类

调整钱我们先要卸载挂载点,因为挂载后是使用状态,不允许操作。如图,卸载成功。

# umount /LVM

未分类

检查文件系统是否有坏块,这部检查必须要做。

# e2fsck -f /dev/mapper/vgdata-lvData

未分类

从上面df -h 知道,总空间287M,使用128M,剩余146M空间。我们缩小总空间到250M,做演示。

注意:缩小LV前,先要缩小PV,resize2fs在前,lvreduce在后,顺序不能错。

# resize2fs /dev/mapper/vgdata-lvData 250M  //缩小PV

未分类

# lvreduce -L 250M /dev/mapper/vgdata-lvData
或
# lvreduce -L -50M /dev/mapper/vgdata-lvData  //-50M,在原基础上减去50M空间。

未分类

好了,缩减成功,挂载看看。

# mount -a

# mount /dev/vgdata/lvData  /lvm

因为PE默认4M,我们给的250M的PE不一定对其,所以系统会从新计算PE倍数来对其,显示的数就会小于我们写的数。

未分类

注意:/dev/mapper/vgdata-lvData和/dev/vgdata/lvData是一样的,指向同一路径。

查看PV有多少空闲空间。显示多出48M的空闲空间。

# pvs

未分类

0x03:LV测试篇

写此文章的时候,我就在想如果物理磁盘空间不够,但是LV分配很大,会发生什么现象。

看下图,我在虚拟机里创建了一个5G的虚拟磁盘文件放到D盘。我的电脑D盘,用一些其他东西故意填满,只留下了很少的空闲空间。

下面还有个3G的磁盘,我放到了C盘,C盘空闲空间充足。

未分类

接着将上面创建两个盘在系统里转换成PV物理卷->加入VG卷组->加入LV卷。

未分类

LVM的存放数据的规律是由那个PV先被添加就先存放到哪个PV上,直到PV存满才到下一个PV上存。

sde1就是我们放到上图显示D盘的那个文件,一会写文件先往sde1里写,然后在往sdf1里写。

我们找来一个ISO镜像(大于4G的文件),来往里面拷贝数据,看看发生什么?

未分类

上传数据的过程中,D盘空间用完了,LVM而并没有尝试切换到sdf1的3G这空间去复制,而是直接报了系统错误,而且系统因为没有空间,直接退出了,重新启动都没成功,只好将D盘里删除一些文件,才将系统重新启动。

未分类

总结,PV的设置最大值不能超过物理磁盘的空间,否则会出现丢失数据的问题。

0x04:LVM快照

(转:http://www.linuxidc.com/Linux/2017-05/143774.htm)。

LVM快照是一种以空间换时间时间的方式制作的lvm卷副本。它只在lvm中工作,并只在源逻辑卷发生改变时占用快照卷的空间。如果源卷的变化达到1GB这么大,快照卷同样也会产生这样大的改变。因而,对于空间有效利用的最佳途径,就是总是进行小的修改。如果快照将存储空间消耗殆尽,我们可以使用lvextend来扩容。而如果我们需要缩减快照所占用卷的大小,可以使用lvreduce。实验如下:目标逻辑卷信息如下:

$ pvs
PV         VG   Fmt  Attr PSize PFree
/dev/sdb   vg0  lvm2 a--  7.00g    0 
/dev/sdd1  vg0  lvm2 a--  7.00g 1.99g
$ vgs
VG   #PV #LV #SN Attr   VSize  VFree
vg0    2   1   0 wz--n- 13.99g 1.99g
$ lvs
LV   VG   Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
lv0  vg0  -wi-ao---- 12.00g

现在对逻辑卷lv0创建快照,命名为snaplv0

$ lvcreate -s -n snaplv0 -p r -L 1G /dev/vg0/lv0
Logical volume "snaplv0" created.
$ vgs
VG   #PV #LV #SN Attr   VSize  VFree   
vg0    2   2   1 wz--n- 13.99g 1016.00m
$ lvs
LV   VG   Attr   LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
lv0     vg0  owi-aos--- 12.00g 
snaplv0 vg0  sri-a-s---  1.00g      lv0    0.00

这里/dev/vg0/lv0的挂载点为/mnt。往/mnt里面写入300MB的随机文件,再观察快照情况,可以看 到,快照对应的Data一项有所增长:

$ dd if=/dev/urandom of=/mnt/2.txt bs=1M count=300
300+0 records in
300+0 records out
314572800 bytes (315 MB) copied, 27.5877 s, 11.4 MB/s
$ ls
1.txt  2.txt  data
$ lvs
LV   VG   Attr   LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
lv0  vg0  owi-aos--- 12.00g
snaplv0 vg0  sri-a-s---  1.00g      lv0    29.42

用snaplv0对逻辑卷进行恢复,注意恢复之前需要先将对应的逻辑卷卸载。恢复之后可以看到,原有的snaplv0消失,因此可以得出结论,LVM的快照是一次性的:

$ umount /mnt
$ lvconvert --merge /dev/vg0/snaplv0
Merging of volume snaplv0 started.
lv0: Merged: 71.0%
lv0: Merged: 91.9%
lv0: Merged: 100.0%
$ ls /dev/vg0
lv0
$ mount /dev/vg0/lv0 /mnt
$ ls /mnt
1.txt  data

如果想要删除LVM快照,用lvremove命令,后面跟上快照设备文件的绝对路径即可,例如:

$ lvremove /dev/vg0/snaplv0

0x05:删除LVM

删除LVM,先取消开机自动挂载,在取消挂载、取消LV、取消VG、取消PV,还原磁盘83类型。

# umount /lvm                            //取消挂载
# lvremove /dev/vgdata/lvData                //删除LV
# vgremove vgdata                            //删除vgdata组
# pvremove /dev/sdb1 /dev/sdc1 /dev/sdd1   //磁盘还原成普通磁盘
#  fdisk /dev/sdb1  //执行t ID输入83,让磁盘恢复普通磁盘。

Linux两块磁盘挂载指向一个文件夹LVM磁盘管理(一)

注意:任何磁盘的操作有可能损坏里面数据,请提前备份数据,切记!切记!切记!

0x00:前言

在Linux使用过程中,发现一个文件很大,比如5G,但是有两块物理磁盘一个剩下4G,一个剩3G,磁盘空间不够,这样肯定不能放进去。如果把5G文件分割了是可以放进去,但是如果有很多文件呢!这时候就可以用LVM来帮我们来管理文件是放到哪个磁盘里。

注意:LVM用于单块硬盘小于2TB的分区,如果超过2TB用part分区,不建议用LVM会识别不了。

0x01:文本对照

物理磁盘:即你购买来能拿在手里的那一块磁盘。

PV:物理卷(physical volume)。物理磁盘创建成普通磁盘83后,将类型修改成8e时,其成为LVM磁盘系统,也就是我们说的PV。

VG:逻辑卷组(Volume Group)。是将一个个的PV放到一个组里统一管理。

LV:逻辑卷(logical volume)。也就是从VG中划分的逻辑分区,在这上我们可以当成普通磁盘去使用,新建一个文件或文件夹。

0x02:版本说明

1)VMware Workstation 12 Pro 12.5.7 build-5813279
2)CentOS release 6.9 (Final)

0x03:实验环境搭建

1)安装VM虚拟机以及CentOS系统安装网上很多,略。

2)在VM里创建模拟物理磁盘,虚拟机里会自动识别。

未分类

未分类

未分类

因为做实验节省时间,所以我们将3个磁盘只分了100M、200M、300M,

从容量上我们也可以直观看到在操作的磁盘。

未分类

注意文件名不要重复

未分类

另外2个创建是一样的,重复上面步骤即可。

未分类

在系统中用命令查看,多出几块未分配的磁盘。

# fdisk -l

未分类

3)首先,把磁盘格式化成普通磁盘。

#fdisk /dev/sda

未分类

未分类

0x04:安装LVM,及创建。

将一块普通磁盘类型修改成8e时,其已经成为LVM磁盘系统里,也就是我们说的PV。

磁盘创建好了,但是LVM并不是系统自带的,尤其是2.6.9以下,需要我们自己安装。

查看系统是否安装。

rpm -qa | gre lvm

并查看内核版本。

uname -a

系统显示没有安装,我们用命令安装。

yum -y install lvm2

未分类

1)创建PV。

LVM提示已经安装完成,用pvscan命令提示没有发现PV(physical volumes)

未分类

创建PV,并重新扫描,发现了一个新的PV。

# pvcreate /dev/sdb1
# pvscan

未分类

显示PV信息,因为只创建一个PV,所以只有一个。

# pvdisplay

未分类

好了,现在将一块普通磁盘改变成LVM里最基本物理磁盘。下面我们来创建VG(磁盘管理组)。

2)创建VG(卷组),来管理PV。

# vgscan  //因为之前没有创建过VG,所以扫描没有显示。
# vgcreate vgdata /dev/sdb1   //创建vgdata并将/dev/sdb1加入
#  vgcreate vgdata /dev/sdb1  -s 8M //-s是指定PE大小,默认是4M
# vgdisplay  //显示VG信息

未分类

再次扫描,发现上面创建的“vgdata”卷组VG了。

未分类

3)有了卷组我们就可以创建LV,LV是我们真正用来写数据的,比如新建一个文本等。

# lvscan //扫描LV,之前没有建立过LV,什么也没显示
# lvcreate -L 100M -n lvData vgdata //创建LV,-L 指定LV大小为100M,-n LV名字方便区分,
vgdata 加入到vgdata组,上面创建的。
# lvdisplay

未分类

4)格式化LV及挂载

# mkfs.ext4 /dev/vgdata/lvData  //格式化lvData为ext4格式。
#  mkdir /LVM  //创建挂载点
#  mount /dev/vgdata/lvData  /LVM  //挂载到LVM下
#  df -h  显示挂载成功100M空间系统占用1.6M还要卷组占用一些,实际占用2%。

未分类

好了,到此一个完整的LVM就创建完了。

0x05:开机自动挂载

挂载点的磁盘,在重启后就会丢失,需要将配置写入/etc/fstab,让系统自动挂载。

# echo "/dev/vgdata/lvData  /LVM    ext4    defaults 0 0" >> /etc/fstab

未分类

新玩法,CentOS7中LVM通过扩展逻辑卷扩展swap空间

在我们日常运维工作中,偶尔也会遇到需要扩展swap空间的操作。扩展swap空间的方法很多,现在让我们一起来探讨一下,在LVM下扩展swap空间的方法。

1、查看一下卷组,是否还有空闲空间能用于扩展swap空间。

[root@Geeklp201 ~]# vgdisplay

未分类

从倒数第二行,我们可以看到,本机centos卷组的空闲空间小于5GB,分出1GB来扩展swap空间足够了。
  
2、查看逻辑卷。

[root@Geeklp201 ~]# lvdisplay

未分类
  
逻辑卷swap的路径为/dev/centos/swap。扩展逻辑卷swap。
  

[root@Geeklp201 ~]# lvextend -L 2GB /dev/centos/swap
Size of logical volume centos/swap changed from 1.00 GiB (256 extents) to 2.00 GiB (512 extents).
Logical volume centos/swap successfully resized.

扩展成功!然而,用free命令看一下,当前swap空间并未增加。还需要执行以下几步:
  

[root@Geeklp201 ~]# swapoff /dev/centos/swap
[root@Geeklp201 ~]# mkswap /dev/centos/swap
mkswap: /dev/centos/swap: warning: wiping old swap signature.

正在设置交换空间版本 1,大小 = 2097148 KiB
  
无标签,UUID=4250fdac-92c1-43f4-b266-c9d9c69a2783

[root@Geeklp201 ~]# swapon /dev/centos/swap

未分类

增加成功!都不用去修改fstab文件,是不是很方便?

挂载kvm虚拟机windows虚拟机镜像文件

1、先用losetup 命令关联loop设备与虚拟机文件

losetup -f 命令可以查看目前空闲的loop设备,使用losetup -a 命令可以查看使用的loop设备的关联情况

关联命令为

losetup /dev/loop0 /root/win2003.img

关闭关联命令为 losetup -d /dev/loop0

2、使用kpartx 命令将映射分区

kpartx -av /dev/loop0

参数-a 表示添加映射关系,-v表示显示映射的对应关系

映射成功的设备在/dev/mapper下面,比如/dev/mapper/loop0p1

3、适应mount命令挂载,因为默认不能识别ntfs分区,需要先安装ntfs-3g软件

ntfs-3g依赖fuse,先安装

yum install fuse -y

下载ntfs-3g(下载页面 http://www.tuxera.com/community/ntfs-3g-download/)

wget http://tuxera.com/opensource/ntfs-3g_ntfsprogs-2011.4.12.tgz
tar -zxvf ntfs-3g_ntfsprogs-2011.4.12.tgz
./configuer
make 
make install
mount -t ntfs-3g /dev/mapper/loop0p1 /mnt

完成后依次关闭

umount /mnt
kpartx -dv /dev/loop0
losetup -d /dev/loop0

kubeadm快速部署kubernetes

1、环境准备

准备了三台机器作安装测试工作,机器信息如下:

未分类

2、安装docker

tee /etc/yum.repos.d/docker.repo <<-'EOF'
[dockerrepo]
name=Docker Repository
baseurl=https://yum.dockerproject.org/repo/main/centos/$releasever/
enabled=1
gpgcheck=1
gpgkey=https://yum.dockerproject.org/gpg
EOF

yum update -y && yum upgrade -y
yum install docker-engine -y
systemctl start docker
systemctl enable docker.service

3、安装k8s工具包

三种方式:官方源安装、非官方源安装和release工程编译,yum方式因为不能直接使用google提供的源,非官方源中提供的版本比较老(mritd提供的源很不错,版本很新),如果要使用新版本,可以尝试release工程编译的方式。

博主提供

一些比较懒得同学:-D,可以直接从博主提供的位置下载RPM工具包安装,下载地址: http://abyun.org/wp-content/themes/begin/inc/go.php?url=https://github.com/CloudNil/kubernetes-library/tree/master/rpm_x86_64/For_kubelet_1.5.2

yum install -y socat

rpm -ivh kubeadm-1.6.0-0.alpha.0.2074.a092d8e0f95f52.x86_64.rpm  kubectl-1.5.1-0.x86_64.rpm  kubelet-1.5.1-0.x86_64.rpm  kubernetes-cni-0.3.0.1-0.07a8a2.x86_64.rpm

systemctl enable kubelet.service

官方源安装

跨越GFW方式不细说,你懂的。

建议使用yumdownloader下载rpm包,不然那下载速度,会让各位对玩k8s失去兴趣的。

yum install -y yum-utils

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://yum.kubernetes.io/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
       https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF

yumdownloader kubelet kubeadm kubectl kubernetes-cni
rpm -ivh *.rpm
systemctl enable kubelet.service && systemctl start kubelet

非官方源安装

#感谢mritd维护了一个yum源
tee /etc/yum.repos.d/mritd.repo << EOF
[mritdrepo]
name=Mritd Repository
baseurl=https://rpm.mritd.me/centos/7/x86_64
enabled=1
gpgcheck=1
gpgkey=https://cdn.mritd.me/keys/rpm.public.key
EOF
yum makecache
yum install -y kubelet kubectl kubernetes-cni kubeadm
systemctl enable kubelet && systemctl start kubelet

relese编译

git clone https://github.com/kubernetes/release.git
cd release/rpm
./docker-build.sh

编译完成后生成rpm包到:/output/x86_64,进入到该目录后安装rpm包,注意选择amd64的包(相信大多数同学都是64bit环境,如果是32bit或者arm架构请自行选择安装)。

4、下载docker镜像

kubeadm方式安装kubernetes集群需要的镜像在docker官方镜像中并未提供,只能去google的官方镜像库:gcr.io 中下载,GFW咋办?翻墙!也可以使用docker hub做跳板自己构建,这里针对k8s-1.5.2我已经做好镜像,各位可以直接下载,dashboard的版本并未紧跟kubelet主线版本,用哪个版本都可以,本文使用kubernetes-dashboard-amd64:v1.5.0。

kubernetes-1.5.2所需要的镜像:

  • etcd-amd64:2.2.5
  • kubedns-amd64:1.9
  • kube-dnsmasq-amd64:1.4
  • dnsmasq-metrics-amd64:1.0
  • exechealthz-amd64:1.2
  • pause-amd64:3.0
  • kube-discovery-amd64:1.0
  • kube-proxy-amd64:v1.5.2
  • kube-scheduler-amd64:v1.5.2
  • kube-controller-manager-amd64:v1.5.2
  • kube-apiserver-amd64:v1.5.2
  • kubernetes-dashboard-amd64:v1.5.0

偷下懒吧,直接执行以下脚本:

#!/bin/bash
images=(kube-proxy-amd64:v1.5.2 kube-discovery-amd64:1.0 kubedns-amd64:1.9 kube-scheduler-amd64:v1.5.2 kube-controller-manager-amd64:v1.5.2 kube-apiserver-amd64:v1.5.2 etcd-amd64:2.2.5 kube-dnsmasq-amd64:1.4 dnsmasq-metrics-amd64:1.0 exechealthz-amd64:1.2 pause-amd64:3.0 kubernetes-dashboard-amd64:v1.5.0 nginx-ingress-controller:0.8.3)
for imageName in ${images[@]} ; do
  docker pull cloudnil/$imageName
  docker tag cloudnil/$imageName gcr.io/google_containers/$imageName
  docker rmi cloudnil/$imageName
done

5、安装master节点

由于kubeadm和kubelet安装过程中会生成/etc/kubernetes目录,而kubeadm init会先检测该目录是否存在,所以我们先使用kubeadm初始化环境。

kubeadm reset && systemctl start kubelet
kubeadm init --api-advertise-addresses=172.16.1.101 --use-kubernetes-version v1.5.2
#如果使用外部etcd集群:
kubeadm init --api-advertise-addresses=172.16.1.101 --use-kubernetes-version v1.5.2 --external-etcd-endpoints http://172.16.1.107:2379,http://172.16.1.107:4001

说明:如果打算使用flannel网络,请加上:–pod-network-cidr=10.244.0.0/16。如果有多网卡的,请根据实际情况配置–api-advertise-addresses=,单网卡情况可以省略。

如果出现ebtables not found in system path的错误,要先安装ebtables包,我安装的过程中未提示,该包系统已经自带了。

yum install -y ebtables
  • 1

安装过程大概2-3分钟,输出结果如下:

[kubeadm] WARNING: kubeadm is in alpha, please do not use it for production clusters.
[preflight] Running pre-flight checks
[init] Using Kubernetes version: v1.5.2
[tokens] Generated token: "064158.548b9ddb1d3fad3e"
[certificates] Generated Certificate Authority key and certificate.
[certificates] Generated API Server key and certificate
[certificates] Generated Service Account signing keys
[certificates] Created keys and certificates in "/etc/kubernetes/pki"
[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/kubelet.conf"
[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/admin.conf"
[apiclient] Created API client, waiting for the control plane to become ready
[apiclient] All control plane components are healthy after 61.317580 seconds
[apiclient] Waiting for at least one node to register and become ready
[apiclient] First node is ready after 6.556101 seconds
[apiclient] Creating a test deployment
[apiclient] Test deployment succeeded
[token-discovery] Created the kube-discovery deployment, waiting for it to become ready
[token-discovery] kube-discovery is ready after 6.020980 seconds
[addons] Created essential addon: kube-proxy
[addons] Created essential addon: kube-dns

Your Kubernetes master has initialized successfully!

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
    http://kubernetes.io/docs/admin/addons/

You can now join any number of machines by running the following on each node:

kubeadm join --token=de3d61.504a049ec342e135 172.16.1.101

6、安装minion节点

Master节点安装好了Minoin节点就简单了。

kubeadm reset && systemctl start kubelet
kubeadm join --token=de3d61.504a049ec342e135 172.16.1.101
  • 1
  • 2

输出结果如下:

[kubeadm] WARNING: kubeadm is in alpha, please do not use it for production clusters.
[preflight] Running pre-flight checks
[preflight] Starting the kubelet service
[tokens] Validating provided token
[discovery] Created cluster info discovery client, requesting info from "http://172.16.1.101:9898/cluster-info/v1/?token-id=f11877"
[discovery] Cluster info object received, verifying signature using given token
[discovery] Cluster info signature and contents are valid, will use API endpoints [https://172.16.1.101:6443]
[bootstrap] Trying to connect to endpoint https://172.16.1.101:6443
[bootstrap] Detected server version: v1.5.2
[bootstrap] Successfully established connection with endpoint "https://172.16.1.101:6443"
[csr] Created API client to obtain unique certificate for this node, generating keys and certificate signing request
[csr] Received signed certificate from the API server:
Issuer: CN=kubernetes | Subject: CN=system:node:yournode | CA: false
Not before: 2016-12-15 19:44:00 +0000 UTC Not After: 2017-12-15 19:44:00 +0000 UTC
[csr] Generating kubelet configuration
[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/kubelet.conf"

Node join complete:
* Certificate signing request sent to master and response
  received.
* Kubelet informed of new secure connection details.

Run 'kubectl get nodes' on the master to see this machine join.

安装完成后可以查看下状态:

[root@master ~]# kubectl get nodes
NAME       STATUS         AGE
master     Ready,master   6m
minion01   Ready          2m
minion02   Ready          2m

7、安装Calico网络

网络组件选择很多,可以根据自己的需要选择calico、weave、flannel,calico性能最好,weave和flannel差不多。Addons中有配置好的yaml,部署环境使用的阿里云的VPC,官方提供的flannel.yaml创建的flannel网络有问题,所以本文中尝试calico网络,。

kubectl apply -f http://docs.projectcalico.org/v2.0/getting-started/kubernetes/installation/hosted/kubeadm/calico.yaml
  • 1

如果使用了外部etcd,去掉其中以下内容,并修改etcd_endpoints: [ETCD_ENDPOINTS]:

---

# This manifest installs the Calico etcd on the kubeadm master.  This uses a DaemonSet
# to force it to run on the master even when the master isn't schedulable, and uses
# nodeSelector to ensure it only runs on the master.
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: calico-etcd
  namespace: kube-system
  labels:
    k8s-app: calico-etcd
spec:
  template:
    metadata:
      labels:
        k8s-app: calico-etcd
      annotations:
        scheduler.alpha.kubernetes.io/critical-pod: ''
        scheduler.alpha.kubernetes.io/tolerations: |
          [{"key": "dedicated", "value": "master", "effect": "NoSchedule" },
           {"key":"CriticalAddonsOnly", "operator":"Exists"}]
    spec:
      # Only run this pod on the master.
      nodeSelector:
        kubeadm.alpha.kubernetes.io/role: master
      hostNetwork: true
      containers:
        - name: calico-etcd
          image: gcr.io/google_containers/etcd:2.2.1
          env:
            - name: CALICO_ETCD_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
          command: ["/bin/sh","-c"]
          args: ["/usr/local/bin/etcd --name=calico --data-dir=/var/etcd/calico-data --advertise-client-urls=http://$CALICO_ETCD_IP:6666 --listen-client-urls=http://0.0.0.0:6666 --listen-peer-urls=http://0.0.0.0:6667"]
          volumeMounts:
            - name: var-etcd
              mountPath: /var/etcd
      volumes:
        - name: var-etcd
          hostPath:
            path: /var/etcd

---

# This manfiest installs the Service which gets traffic to the Calico
# etcd.
apiVersion: v1
kind: Service
metadata:
  labels:
    k8s-app: calico-etcd
  name: calico-etcd
  namespace: kube-system
spec:
  # Select the calico-etcd pod running on the master.
  selector:
    k8s-app: calico-etcd
  # This ClusterIP needs to be known in advance, since we cannot rely
  # on DNS to get access to etcd.
  clusterIP: 10.96.232.136
  ports:
    - port: 6666

检查各节点组件运行状态:

[root@master work]# kubectl get po -n=kube-system -o wide
NAME                                       READY     STATUS    RESTARTS   AGE       IP                NODE
calico-node-0jkjn                          2/2       Running   0          25m       172.16.1.101      master
calico-node-w1kmx                          2/2       Running   2          25m       172.16.1.106      minion01
calico-node-xqch6                          2/2       Running   0          25m       172.16.1.107      minion02
calico-policy-controller-807063459-d7z47   1/1       Running   0          11m       172.16.1.107      minion02
dummy-2088944543-qw3vr                     1/1       Running   0          29m       172.16.1.101      master
kube-apiserver-master                      1/1       Running   0          28m       172.16.1.101      master
kube-controller-manager-master             1/1       Running   0          29m       172.16.1.101      master
kube-discovery-1769846148-lzlff            1/1       Running   0          29m       172.16.1.101      master
kube-dns-2924299975-jfvrd                  4/4       Running   0          29m       192.168.228.193   master
kube-proxy-6bk7n                           1/1       Running   0          28m       172.16.1.107      minion02
kube-proxy-6pgqz                           1/1       Running   1          29m       172.16.1.106      minion01
kube-proxy-7ms6m                           1/1       Running   0          29m       172.16.1.101      master
kube-scheduler-master                      1/1       Running   0          28m       172.16.1.101      master

说明:kube-dns需要等calico配置完成后才是running状态。

8、部署Dashboard

下载kubernetes-dashboard.yaml

curl -O https://rawgit.com/kubernetes/dashboard/master/src/deploy/kubernetes-dashboard.yaml
  • 1

修改配置内容,#——内是修改的内容,调整目的:部署kubernetes-dashboard到default-namespaces,不暴露端口到HostNode,调整版本为1.5.0,imagePullPolicy调整为IfNotPresent。

kind: Deployment
apiVersion: extensions/v1beta1
metadata:
  labels:
    app: kubernetes-dashboard
  name: kubernetes-dashboard
#----------
#  namespace: kube-system
#----------
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kubernetes-dashboard
  template:
    metadata:
      labels:
        app: kubernetes-dashboard
      annotations:
        scheduler.alpha.kubernetes.io/tolerations: |
          [
            {
              "key": "dedicated",
              "operator": "Equal",
              "value": "master",
              "effect": "NoSchedule"
            }
          ]
    spec:
      containers:
      - name: kubernetes-dashboard
        #----------
        image: gcr.io/google_containers/kubernetes-dashboard-amd64:v1.5.0
        imagePullPolicy: IfNotPresent
        #----------
        ports:
        - containerPort: 9090
          protocol: TCP
        args:
          # Uncomment the following line to manually specify Kubernetes API server Host
          # If not specified, Dashboard will attempt to auto discover the API server and connect
          # to it. Uncomment only if the default does not work.
          # - --apiserver-host=http://my-address:port
        livenessProbe:
          httpGet:
            path: /
            port: 9090
          initialDelaySeconds: 30
          timeoutSeconds: 30
---
kind: Service
apiVersion: v1
metadata:
  labels:
    app: kubernetes-dashboard
  name: kubernetes-dashboard
#----------
#  namespace: kube-system
#----------
spec:
#----------
#  type: NodePort
#----------
  ports:
  - port: 80
    targetPort: 9090
  selector:
    app: kubernetes-dashboard

9、Dashboard服务暴露到公网

kubernetes中的Service暴露到外部有三种方式,分别是:

  • LoadBlancer Service
  • NodePort Service
  • Ingress

LoadBlancer Service是kubernetes深度结合云平台的一个组件;当使用LoadBlancer Service暴露服务时,实际上是通过向底层云平台申请创建一个负载均衡器来向外暴露服务;目前LoadBlancer Service支持的云平台已经相对完善,比如国外的GCE、DigitalOcean,国内的 阿里云,私有云 Openstack 等等,由于LoadBlancer Service深度结合了云平台,所以只能在一些云平台上来使用。

NodePort Service顾名思义,实质上就是通过在集群的每个node上暴露一个端口,然后将这个端口映射到某个具体的service来实现的,虽然每个node的端口有很多(0~65535),但是由于安全性和易用性(服务多了就乱了,还有端口冲突问题)实际使用可能并不多。

Ingress可以实现使用nginx等开源的反向代理负载均衡器实现对外暴露服务,可以理解Ingress就是用于配置域名转发的一个东西,在nginx中就类似upstream,它与ingress-controller结合使用,通过ingress-controller监控到pod及service的变化,动态地将ingress中的转发信息写到诸如nginx、apache、haproxy等组件中实现方向代理和负载均衡。

9.1 部署Nginx-ingress-controller

Nginx-ingress-controller是kubernetes官方提供的集成了Ingress-controller和Nginx的一个docker镜像。

apiVersion: v1
kind: ReplicationController
metadata:
  name: nginx-ingress-controller
  labels:
    k8s-app: nginx-ingress-lb
spec:
  replicas: 1
  selector:
    k8s-app: nginx-ingress-lb
  template:
    metadata:
      labels:
        k8s-app: nginx-ingress-lb
        name: nginx-ingress-lb
    spec:
      terminationGracePeriodSeconds: 60
      hostNetwork: true
      #本环境中的minion02节点有外网IP,并且有label定义:External-IP=true
      nodeSelector:
        External-IP: true
      containers:
      - image: gcr.io/google_containers/nginx-ingress-controller:0.8.3
        name: nginx-ingress-lb
        imagePullPolicy: IfNotPresent
        readinessProbe:
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
        livenessProbe:
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          timeoutSeconds: 1
        env:
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: POD_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
        args:
        - /nginx-ingress-controller
        - --default-backend-service=$(POD_NAMESPACE)/kubernetes-dashboard

9.2 部署Ingress

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: k8s-dashboard
spec:
  rules:
  - host: dashboard.cloudnil.com
    http:
      paths:
      - path: /
        backend:
          serviceName: kubernetes-dashboard
          servicePort: 80

部署完Ingress后,解析域名dashboard.cloudnil.com到minion02的外网IP,就可以使用dashboard.cloudnil.com访问dashboard。

10、注意事项

kubeadm目前还在开发测试阶段,不建议在生产环境中使用kubeadm部署kubernetes环境。此外,使用kubeadm是需要注意以下几点:

10.1 单点故障

当前版本的kubeadm暂且不能部署真正高可用的kubernetes环境,只具有单点的master环境,如采用内置etcd,那etcd也是单节点,若master节点故障,可能存在数据丢失的情况,所以建议采用外部的etcd集群,这样即使master节点故障,那只要重启即可,数据不会丢失,高可用的部署功能据说正在开发中,很快就可以发布使用。

10.2 暴露主机端口

POD实例配置中的HostPort和HostIP参数无法用于使用了CNI网络插件的kubernetes集群环境,如果需要暴露容器到主机端口,可以使用NodePort或者HostNetwork。

10.3 CentOS环境路由错误

RHEL/CentOS7 环境中iptables的策略关系,会导致路由通讯错误,需要手动调整iptables的桥接设置:

# cat /etc/sysctl.d/k8s.conf
 net.bridge.bridge-nf-call-ip6tables = 1
 net.bridge.bridge-nf-call-iptables = 1

10.4 Token丢失

Master节点部署完成之后,会输出一个token用于minion节点的配置链接,不过这个token没有很方便的查看方式,导致此日志输出关闭后,没有token无法join minion节点,可以通过下述方式查看token:

kubectl -n kube-system get secret clusterinfo -o yaml | grep token-map | awk '{print $2}' | base64 --decode | sed "s|{||g;s|}||g;s|:|.|g;s/"//g;" | xargs echo
  • 1

建议提前使用kubeadm token命令生成token,然后在执行kubeadm init和kubeadm join的使用通过–token指定token。

10.5 Vagrant中主机名的问题

如果使用Vagrant虚拟化环境部署kubernetes,首先得确保hostname -i能够获取正确的通讯IP,默认情况下,如果/etc/hosts中未配置主机名与IP的对应关系,kubelet会取第一个非lo网卡作为通讯入口,若这个网卡不做了NAT桥接的网卡,那安装就会出现问题。

腾讯云多Kubernetes的多维度监控实践

本次内容根据2017年11月4日 K8S Geek Gathering 沙龙深圳站腾讯云高级工程师王天夫的演讲内容整理而成。

本次分享的主要内容涉及腾讯云容器的顶层整体设计,包括产品功能,及提供的附加能力。同时会介绍我们现在Master集群化部署的整体方案。通过这些内容的提前了解,可以更好理解后面和大家分享的关于容器监控的内容,所有监控的设计都是依赖于Master集群化部署的。最后会和大家分享腾讯云容器服务监控的Future Work。

未分类

大家可以看一下这个图,这是腾讯云容器服务PaaS平台顶层的设计,最上面是云Portal,意义是用户在使用我们容器服务的时候能够从这几个维度去掌控他们的集群、创建他们的容器。第一个是MC,可以理解为是控制管理台,大家都知道Kubernetes本身的概念是比较复杂的,对一个刚刚接手Kubernetes的人来说理解成本是特别大的,我们在Kubernetes之上包装了它的概念,对于刚刚接手的人来说是非常好的理解。同时可视化出来提供页面给大家用。第二点是支持原生的K8S API,因为整个容器服务是基于K8S开发的,为了保证用户使用不同的Kubernetes,所以我们在Kubernetes主干上并不会去做很大的改动,因为一开始我们是做过这方面的东西,但是我们发现如果我们在K8S上做了特别大的改动,在第二次提供给用户或者升级的时候,是一个非常困难的事情,因为大家知道K8S的迭代是非常快的,大概是半年到一年时间就会升级一个大版本,所以我们基本上都是原生基于K8S开发。最后我们还把我们自己包装的概念通过一个云API提供给用户使用,因为现在很多的用户都是有自己的运营系统的,他们会使用云API去封装一些自己的运营平台,所以我们这里也支持了一下。

中间这块是整个容器服务三个大部分,第一块是整个CCS,这块提供了如下的功能,像集群管理、模板应用管理,应用管理这里指的是我们会把所有的服务包装成一个大的应用,方便用户去一键部署自己的应用。第三个是服务管理,我们把K8S里面提到的概念,像deployment,service,pod封装成服务的概念提供给用户,后面还有日志、券和配额,这些都是我们这边开发的。最底层,因为我们要支持原生的Kubernetes,所以不可避免的需要有些开发,比如和IaaS层、PaaS层的打通,就需要有日志、网络、券、负载均衡的驱动开发。第二块是CCR,是我刚才提到的镜像服务。镜像服务支持有多个hub源的镜像,还有自建的Cloud的镜像,还有第三方的也支持。同时我们做了一些比较重要的优化,我们在海外搭建了很多节点,帮助用户能够快速的拉取镜像,并且做成mirror,同时我们的镜像仓库是分地域部署。同时我们还会定时拉去Docker Hub上的镜像做缓存,进一步提升效率。最后一块是CI/CD,CI/CD是去定义自动部署、自动构建的策略,例如提交代码时自动触发。

下面是我现在负责的CCS-Monitor Server,包括监控上面整套容器服务的体系。最底下是对我们自己腾讯云的IaaS和PaaS层的集合,譬如说CVM、黑石,大家可以理解为公有云和私有云,同时我们集成块存储、对象存储、CFS,我们还有日志中心,后面我会讲一下。最后还有弹性伸缩和负载均衡,弹性伸缩主要可以理解为HPA和HNA,这是腾讯服务顶层的计。

未分类

接下来第二点,给大家讲一下腾讯云Master集群化部署。下图是现在腾讯容器服务Master集群化部署的概览,我给大家说一下大概的背景。当初腾讯云的容器服务刚开始上线的时候,这个地方并不是这样子的。

刚开始我们会为用户的每个集群创建一个Master,这个Master当初是一个虚拟机,为了做高可用,我们会为用户再部署一个stand by的Master,当Master出现故障的时候,我们可以方便的切换。

最后就造成很多多的问题,一是成本的问题,如果每个集群都部署一个Master,部署一台虚拟机,成本很大。二是运维成本,每台Master都是一台虚拟机,每个master的组件,是一个二进制文件部署在Master上面。这种情况下,如果对某个Master进行升级,不可避免的就会出现很多问题。

基于这个考虑,我们重新优化了整个我们的Master部署,我们采用的方案是调研了社区里面一些热门的方案,这个方案就是kubernetes in kubernetes,不知道大家有没有了解过这个东西。我们单独部署一套K8S集群,所有Master的组件,大家知道的三大组件都会以pod的形式运行在K8S集群中。我们为Pod绑定双网卡,一个网卡是弹性网卡,它会单独与用户的VPC做网络通信,另外一个网卡是原生的,这个网卡会是Master集群中使用的网卡。

每个API的组件都是一个Pod,好处是,一是Master集群的部署,主要是以K8S管理,这样HA、SLA都有很大的保证,包括后面运维的提升,可以使用K8S原生的rolling update去操作。其次是成本,有些用户可能Master不需要那么大的CPU Memory,我们可以共同调整CPU Memory的request,同时对于大型的客户,譬如说在集群中运行了上千个Pod情况下,通过动态调整扩展Master的配置,增大更多的Api server做一个负载调优。

这里大概讲了现在集群化部署的方案,后面我监控的方案都会依赖于这个,给大家稍微先讲一下这块。

未分类

未分类

第三,基础的指标监控。我们的基础指标监控主要还是以IaaS层为主,就是大家所说的Cpu,Memory、DiSK和Network方面。这里一共有四块,Node、Deployment,Deployment,Pod,container,所有IaaS层的监控指标都会依照这四个模块来做聚合。

上面的四块是我讲的IaaS层基础指标,这里我选取了几个重要的指标,如果大家以后有自建容器监控,希望对大家有所帮助。CPU Memory有些指标是非常重要的,例如CPU Usage和Memory Usage,这里的Cpu Usage和Memory Usage是占整个pod request或者 limit的整个比例,如果这两个指标比较高,就必须警觉起来,可能会造成pod不可用的问题发生,另外我提一下,大家知道,在K8S中,有一个request 和limit的概念,如果request limit不配置,在一些测试环境,不知道大家有没有试过,当一个Pod跑到很高的情况下,会出现雪崩的效应,比如跑挂一台机器,这时候挂了之后,节点异常,K8S会自动的把这台机器上所有的Pod踢走,Pod会自动创建到另外的机器上,继续拖垮另外一台机器,这种可以称之为“雪崩效应”。最后造成的结果是K8S集群不可用。其次,CPU node和Memory node。当前你的K8S集群中还有剩余的CPU和Memory可分配的比例,当一个K8S pod配置的request limit不能满足当前集群中所剩余的量,就会造成,新的Pod无法调度。Network比较基本,一个是进出带宽、进出流量,还有进出包量。Disk有几个比较重要的,traffic、iops,这些自己自建的时候也需要关注。

最后单独提一下Inode,有一次用户使用过程发现Pod创建不成功,经过多方面调查,发现Inode满了,为什么出现这种情况?我们看了K8S代码,它对镜像和日志都有回收机制,但是对Inode的回收和清理是没有的,社区也有讨论,但是一直没有解决。所以说Inode这块是必须要监控起来的,它会造成你整个集群中某个节点无法创建服务,所以说我单独把它拎出来和大家提一下,我不知道现在的1.8版本有没有解决这个问题。

最后是LB的监控,大家可以知道,servers有几种提供的访问方式,腾讯云容器服务的servers与腾讯云的LB做了绑定,用户创建servers的时候,如果指定的方式是LB,我们通过插件的方式帮他申请一个LB挂在上面,不管是内网还是外网。用户对自己服务的监控,我们可以通过LB的Httpcode和当前的连接数、回包的时间等指标去做,就能准确的判断出当前业务的健康状态。

未分类

这是基础监控指标大概的架构(见下图)。我们主要使用开源的方式,大家在网上关注监控就知道,容器的监控大概有这么几种方案,当时我们做方案评估的时候也考虑过其他几种,最后还是选择了heapster的方式,还是业务驱动,因为调研的时候发现cadvisor对K8S中的聚合没有做得特别好,它的数据都是原始的数据,如果我们在以Kubernetes的方式聚合,这是很复杂的。普罗米修斯,我们考虑它比较重,一个是集收集,告警和存储一体的,我们需要的仅仅是收集这块,所以说普罗米修斯并不适合我们这里的业务,最后我们就选择使用heapster。我们这里的heapster也是以容器的方式部署在Master集群化部署的集群里面,对用户是无感知的,也不消耗用户的资源。其次heapster我们帮它绑定两张网卡,一张是去用户的集群中拉取监控数据,因为大家知道heapster需要与Kubernetes通信,拉取一些监控数据,所以我们这里必须绑定两张网卡。其次我们会构建一个CCS Monitorserver,定时拉取一些集群的监控数据,做一些汇总或计算。最后,我们会把这些收集到的数据Push到Barad server,这可以理解为腾讯云整个监控的组件,这是平台级的组件。Barad server做了几件事,一是聚合,会把我们所有上报的指标聚合成,比如我们加一些时间粒度的汇总,1分钟、5分钟、10分钟这种,包括我们以Node的形式展示出整个Node下所有pod平均的监控指标。做这种聚合。最后我们会提供云API的方式给接入层使用,接入层主要是用户调取需要的监控指标,还有HPA和HNA,就是Pod和Node水平扩展,这个是我们直接拉取Barad API的数据做扩展工作。

未分类

第四,事件指标。其实在问题发生的时候,如果仅仅只看基础的监控指标是远远不够的,因为你只能发现你的服务出现了问题,但是你不能很好的去知道到底是哪个服务出现了问题,事件指标主要如下几个问题:1、汇聚当前K8S所有资源事件的汇总,我们会根据这些事件做自己的提炼,同时push到事件中心。2、事件中心指标弥补指标监控信息部直接的短板,我刚才说到过。3、提高问题的定位效率。4、事件指标支持告警。事件指标主要分两大块:1、异常事件;2、状态事件。异常事件大家可以理解为Pod创建失败、重启、节点异常、内存不足、调度失败的事件。状态事件是一些正常事件,比如Pod启动、销毁、更新中、HPA触发、HNA触发。它对对于定位问题也有很大的帮助。

未分类

事件指标的整体方案,我们当前是从API server中拉取K8S所有的事件,会存储在ES集群中,我们会有内部的Cluster做数据的查询和展示。ES中汇聚的都是每条基础数据,也就是大家俗称的源数据。其次CCS Monitor会把它合并成用户能够理解的汇总的数据,然后推到腾讯云事件中心去。最后用户可以在控制台上看到这个事件发生的原因、属于哪个资源,最后还会告诉它如何解决这个问题,会有一个帮助文档。

未分类

第五,整个监控中对腾讯最重要的是集群稳定性的监控。这里的图会有点问题,集群稳定性的监控分为四大块,Kube-System和ETCD、Master相关组件监控,比如API server等,最重要的是运行时问题监控。

未分类

集群稳定性监控采用三个开源的方案,一是Node Detector,主要是做运行时。Fluentd主要是采集每个Master集群上每个容器的node,后面也用了普罗米修斯的方案,没有再使用heapster,因为普罗米修斯,我们需要它做一些存储,不需要做对外展示,这是内部使用,所以我们需要采用普罗米修斯去定制一些东西去采集更多的指标。大家可以看到整个Master集群上,每个Master集群上每个node部署的各个pod,Fluentd会拉取lod。普罗米修斯我们自己定制了一些插件,在每个pod上拉取一些我们基本的指标。同时Node Detector部署在每个用户节点上,这是用户可以自己选择的。它主要采集一些Kernel和runtime的问题。Node Detector是K8S官方的项目,如果大家感兴趣可以了解一下。

未分类

第六,最后一个监控组件,业务日志监控。大家知道业务日志对于一个问题定位帮助是非常大的,如果一个监控仅仅只有事件和指标,其实很多问题都无法定位,因为容器在使用的时候,更多的会动态的增加和减少。所以我们这里会采集容器日志,并且保存在日志服务中,供用户在后期能更方便的去追溯到原来的一些业务问题。业务日志分四个板块,容器日志的收集和节点日志的收集,还有日志存储和日志处理,现在容器日志也是前面提到的stdout和stderr日志,并且附加相关的Kubernetes Metadata,主机特定目录的日志并附加指定的label去收集用户容器达到主机上固定的日志。存储方面,我们支持把日志发送到用户自己搭建的Kafka或者ES或者腾讯云的日志服务中存储起来做消费。最后一块是日志处理,日志处理主要是方便用户能够去方便定位问题,同时我们支持能够根据一定关键字配置一些关键字的告警,最后我们后续可能还会支持做一些大数据的处理工作。

未分类

整个业务日志的监控整体的方案(见PPT),我们让用户定义一个个不同的规则,不同的规则可以叫collector,所有的collector会并成一个Config Map,在启动Fluentd的时候会收集Cluster指定的收集策略,最后发送到不同的后端源,当时做这套设计的时候我们考虑其他组件的方案,主要采集的agent,我们考虑了filebeat和fluentd,最后我们采用的还是fluentd,一是基于性能的考虑,fluentd是c和ruby写的,消耗只有在40M左右,filebeat会更大一些。最重要的一点是fluentd支持数据源推的路由,也就是说它能够通过不同的规则、不同的lable去推到不同的终端上。例如我有一条规则A和规则B,它分别推到ES或者Ckafka,所以我们最后就选择了fluentd的方案做业务日志的收集。

未分类

最后讲一下我们后期调研的工作和待开发的工作:1、自定义监控。自定义希望让用户能够自己去定义一些监控指标,自己Push一些监控指标到我们的监控平台。2、调用链追踪和Real-time Monitor的部署,当一个应用起来之后,会有成千上百的容器在里面传输,调用链就是非常直观的监控方向,同时配合realtimemonitor,能够很好的发现服务的健康状态,其次我们还会提供一个应用市场,因为现在普遍上开源也有很多的监控方案,我们会把它打包成一个个应用提供给用户使用,最后两点就是告警的预测和集群网络的监控,告警预测我们希望通过我们收集的数据去分析可能发生的问题,例如说当一个时间点内某项指标与前段时间周期性比较的指标的发生很大差异的时候,我们需要能够及时的通知用户,这里可能会出现了问题。集群网络的监控方面,我们发现用户在部署的集群的时候,经常有些iptables,ACL,或者timeout等网络的问题,这块的监控后期同样会补上。

未分类

Linux iptables防火墙原理与常用配置

Linux系统中,防火墙(Firewall),网址转换(NAT),数据包(package)记录,流量统计,这些功能是由Netfilter子系统所提供的,而iptables是控制Netfilter的工具。iptables将许多复杂的规则组织成成容易控制的方式,以便管理员可以进行分组测试,或关闭、启动某组规则。iptable只读取数据包头,不会给信息流增加负担,也无需进行验证。

iptables结构

  
iptables由4表、5链和用户在链内写入的各种规则所组成。

1、表:容纳各种规则链;

表是按照功能分的类,具体功能如下:

(1)raw表:用来决定是否对数据包进行状态跟踪。(不常用)

(2)mangle表:为数据包设置标记,有ACK、SYN、FIN、RST、PSH、URG等标记。(不常用)

(3)nat表:修改数据包的IP地址、端口等信息。(网关型防火墙常用)

(4)filter表:确定是否放行数据包。(常用)

2、链:容纳各种防火墙规则;

链是按照时机分的类。

(1)input:处理入站请求包

(2)output:处理出站包(就是响应、应答包)

(3)forward:处理转发数据包,实现不同网段间的通信

(4)prerouting:在包做路由选择之前应用此链的规则

(5)postrouting:在数据包做路由选择之后应用此链的规则

表的处理优先级:raw > mangle > nat > filter

详细的数据包流程:

未分类

iptable应用场景

未分类

上图是应用场景的简单拓扑描述,下面的应用场景举例,都以上图为参考.

系统启动的时候所有的默认策略都是ACCEPT,在下面的场景举例中,我们都是在这种前提下设定iptable的。下面每个场景举例都是独立的,没有相关联性的。

网关服务器安全策略

目标 : 网关服务器系统自生安全策略,只对内网用户开放22端口(sshd服务)

#清空 filter table
[root@localhost]# iptables -F -t filter
[root@localhost]# iptables -X -t filter
[root@localhost]# iptables -Z -t filter

#清空 nat table
[root@localhost]# iptables -F -t nat
[root@localhost]# iptables -X -t nat
[root@localhost]# iptables -Z -t nat

#设置默认策略(INPUT链默认为DROP)
[root@localhost]# iptables -t filter -P INPUT DROP
[root@localhost]# iptables -t filter -P OUTPUT ACCEPT
[root@localhost]# iptables -t filter -P FORWARD ACCEPT

#回环接口(lo),默认accept
[root@localhost]# iptables -A INPUT -p ALL -i lo -j ACCEPT

#只对内网用户开放sshd服务
[root@localhost]# iptables -A INPUT -p tcp -s 192.168.138.0/24 --dport 22 -j ACCEPT

说明: 防火墙的策略顺序一般都是 从 非信任 ==> 信任,默认关闭所有访问权限,然后按照需要逐条开放访问权限.

共享上网(nat)

目标:使局域网的用户都可以访问外网的服务器

[root@localhost]# echo 1 > /proc/sys/net/ipv4/ip_forward
[root@localhost]# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

说明: SNAT 和 MASQUERADE 区别

SNAT : 不管是几个地址,必须明确的指定要SNAT的ip,适合网关服务器有固定地址或者是固定地址范围. MASQUERADE : 是针对ADSL动态拨号这种场景而设计,从服务器的网络接口上,自动获取当前ip地址来做NAT,这样就实现了动态SNAT地址转换

内网的服务器对外服务(端口映射)

目标:使外网用户可以访问到局域网192.168.138.21这台HTTP服务

[root@localhost]# echo 1 > /proc/sys/net/ipv4/ip_forward
[root@localhost]# iptables -t nat -A PREROUTING -p tcp -m tcp --dport 80 -j DNAT --to-destination 192.168.138.21
[root@localhost]# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

在网关服务器进行透明代理

目标: 使局域网用户,访问外网web服务时,自动使用squid作web透明代理服务器。

[root@localhost]# echo 1 > /proc/sys/net/ipv4/ip_forward
[root@localhost]# iptables -t nat -A PREROUTING -s 192.168.138.0/24 -p tcp --dport 80 -i eth0 -j DNAT --to 192.168.138.1
[root@localhost]# iptables -t nat -A PREROUTING -s 192.168.138.0/24 -p tcp --dport 80 -i eth0 -j REDIRECT --to 3128 
[root@localhost]# iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE 

注意:iptables写入的规则重启会自动失效,需要使用/etc/rc.d/init.d/iptables save 保存到文件,重启才会自动读取文件上的配置,且使用iptables save保存之后,重启iptables服务:service iptables restart

iptables命令详解

iptables(选项)(参数)

-t<表>:指定要操纵的表; 
-A:向规则链中添加条目; 
-D:从规则链中删除条目; 
-i:向规则链中插入条目; 
-R:替换规则链中的条目; 
-L:显示规则链中已有的条目; 
-F:清楚规则链中已有的条目; 
-Z:清空规则链中的数据包计算器和字节计数器; 
-N:创建新的用户自定义规则链;
-X:用于删除用户自定义的空链,使用方法跟-N相同,但是在删除之前必须要将里面的链给清空; 
-P:定义规则链中的默认目标; 
-h:显示帮助信息; 
-p:指定要匹配的数据包协议类型; 
-s:指定要匹配的数据包源ip地址; 
-j<目标>:指定要跳转的目标; 
-i<网络接口>:指定数据包进入本机的网络接口; 
-o<网络接口>:指定数据包要离开本机所使用的网络接口。

iptables命令选项输入顺序:

iptables -t 表名 <-A/I/D/R> 规则链名 [规则号] <-i/o 网卡名> -p 协议名 <-s 源IP/源子网> 
             --sport 源端口 <-d 目标IP/目标子网> --dport 目标端口 -j 动作

表名包括:

  • raw:高级功能,如:网址过滤。

  • mangle:数据包修改(QOS),用于实现服务质量。

  • nat:地址转换,用于网关路由器。

  • filter:包过滤,用于防火墙规则。

规则链名包括:

  • INPUT链:处理输入数据包。

  • OUTPUT链:处理输出数据包。

  • PORWARD链:处理转发数据包。

  • PREROUTING链:用于目标地址转换(DNAT)。

  • POSTOUTING链:用于源地址转换(SNAT)。

动作包括:

  • ACCEPT:接收数据包。

  • DROP:丢弃数据包。

  • REDIRECT:重定向、映射、透明代理。

  • SNAT:源地址转换。

  • DNAT:目标地址转换。

  • MASQUERADE:IP伪装(NAT),用于ADSL。

  • LOG:日志记录。

构建基于nginx-php-yaf的docker镜像

  • 需求 : php7.1 + nginx
  • php扩展: yaf、redis、ldap、pdo、mbstring、 mcrypt

阅读完本文后,你能解决以下常见问题:

  • 如何写Dockerfile,并通过Dockerfile构建镜像。
  • 如何通过supervisord管理进程,并将进程日志通过docker logs {container}输出

实现步骤

我们的镜像基于centos:7系统, Dockerfile代码如下:

FROM centos:7
MAINTAINER [email protected]
RUN rpm -Uvh http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm 
    && rpm -Uvh https://sp.repo.webtatic.com/yum/el7/webtatic-release.rpm 
    && yum update -y 
    && yum install -y wget 
        sed  
        gcc 
        gcc-c++ 
        gd 
        gd-devel 
        gmp-devel 
        epel-release 
        net-tools 
        ntpdate 
        ntp 
        openssh-clients  
        curl 
        crontabs 
        openssl 
        openssl-devel 
        nginx 
        squid 
        php71w 
        php71w-fpm 
        php71w-gd 
        php71w-soap 
        php71w-pdo_mysql 
        php71w-pear 
        php71w-devel   
        php71w-mbstring 
        php71w-mcrypt 
        php71w-ldap 
    && yum update -y ntp ntpdate kernel-headers 
    && yum clean all 
    && sed -i 's/http_access deny all/#http_access deny all/g' /etc/squid/squid.conf 
    && cd /tmp 
    && wget -O get-pip.py https://bootstrap.pypa.io/get-pip.py 
    && python get-pip.py 
    && pip install supervisor 
    && mkdir -p /etc/supervisor.d/*.conf 
    && pecl install mongodb 
    && pecl install yaf 
    && wget -c https://github.com/phpredis/phpredis/archive/3.1.4.tar.gz 
        && tar zxvf 3.1.4.tar.gz 
        && cd phpredis-3.1.4 
        && phpize 
        && ./configure 
        && make 
        && make install 
        && cd .. 
        && rm -rf phpredis* 
    && rm 3.1.4.tar.gz  
    && echo "" >> /etc/php.ini 
    && echo "extension=redis.so" >> /etc/php.ini 
    && echo "extension=yaf.so" >> /etc/php.ini 
    && echo "extension=mongodb.so" >> /etc/php.ini 
    && echo "[yaf]" >> /etc/php.ini 
    && echo "yaf.use_namespace = 1" >> /etc/php.ini 
COPY ./supervisord.conf /etc/
COPY ./default.conf /etc/nginx/conf.d/
COPY ./nginx.conf /etc/supervisor.d/
COPY ./php.conf /etc/supervisor.d/
COPY ./ntpdate.conf /etc/supervisor.d/
COPY ./nginx.conf.def /etc/nginx/nginx.conf
COPY ./index.php /data/work/code/
EXPOSE 80 443 3128
WORKDIR /data/work/code
CMD ["supervisord","-c","/etc/supervisord.conf"]

问题

子进程stdout如何重定向到supervisord

Supervisor的监督进程supervisord可以捕获所管理子进程的stdout及stderr,并可以配置为写入日志文件
镜像初步构建成功时,运行容器,并通过 docker logs -f {container} 查看容器日志,总是提示错误, 如下:

2017-11-09 07:41:41,256 CRIT uncaptured python exception, closing channel <POutputDispatcher at 36463248 for <Subprocess at 35644984 with name nginx in state RUNNING> (stderr)> (<type 'exceptions.IOError'>:[Errno 29] Illegal seek [/usr/lib/python2.7/site-packages/supervisor/supervisord.py|runforever|227] [/usr/lib/python2.7/site-packages/supervisor/dispatchers.py|handle_read_event|232] [/usr/lib/python2.7/site-packages/supervisor/dispatchers.py|record_output|166] [/usr/lib/python2.7/site-packages/supervisor/dispatchers.py|_log|142] [/usr/lib/python2.7/site-packages/supervisor/loggers.py|info|275] [/usr/lib/python2.7/site-packages/supervisor/loggers.py|log|293] [/usr/lib/python2.7/site-packages/supervisor/loggers.py|emit|186] [/usr/lib/python2.7/site-packages/supervisor/loggers.py|doRollover|211])

经过了N多次查询,N多次尝试,终于找到原因,原来是在配置supervisord管理的子进程文件时,如果配置了stdout_logfile=/dev/stdout, 则必须一块配置stdout_logfile_maxbytes=0

查找的资料说明如下:

If anyone stumbles upon this error like me, be aware that the mentioned options apply to the [supervisord] section, within [program:x] sections, you need to use stdout_logfile_maxbytes = 0and/or stderr_logfile_maxbytes = 0 respectively.

using stdout_logfile=/dev/stdout along with stdout_logfile_maxbytes=0

对于需要将supervisord管理的子进程的日志输出到stdout的program, 配置如下:

[program:php7-fpm]
command=/usr/local/sbin/php-fpm
autostart = true
stderr_logfile = /dev/stdout
stdout_logfile = /dev/stdout
stdout_logfile_maxbytes = 0
stderr_logfile_maxbytes = 0

参见: http://veithen.github.io/2015/01/08/supervisord-redirecting-stdout.html

php-fpm 的错误日志如何定向到docker logs

看到 https://github.com/docker-library/php/issues/63 解释,将error_log及access.log的配置改成如下error_log=/proc/self/fd/2 和 access.log=/proc/self/fd2即可,一直不明白,/proc/self/fd/2和/dev/stdout /dev/stderr有什么联系,经过ls -al /dev 才明白:

lrwxrwxrwx  1 root root   15 Nov  9 07:44 stderr -> /proc/self/fd/2
lrwxrwxrwx  1 root root   15 Nov  9 07:44 stdin -> /proc/self/fd/0
lrwxrwxrwx  1 root root   15 Nov  9 07:44 stdout -> /proc/self/fd/1

对于我们的需求,是将错误及access信息都在docker logs 中显示,所以,我们配置php-fpm.conf如下:

[global]
error_log=/proc/self/fd/1

文件/etc/php-fpm.d/www.conf配置如下:

php_admin_value[error_log] = /proc/self/fd/1
slowlog = /proc/self/fd/1
catch_workers_output = yes
clear_env=no

docker安装mysql5.6

未分类

下载镜像

cjinle@debian:~$ sudo docker pull mysql:5.6
启动mysql
cjinle@debian:~$ sudo docker run --name mysql5.6 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.6
80b766cca7ce0af73787a626153a92286cc7ab8c125e42c1c75e3e680ecefcf5

查看进程

cjinle@debian:~$ sudo docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
80b766cca7ce        mysql:5.6           "docker-entrypoint..."   8 minutes ago       Up 8 minutes        0.0.0.0:3306->3306/tcp   mysql5.6
d4d5aa2e10f7        redis               "docker-entrypoint..."   3 hours ago         Up 3 hours          0.0.0.0:6379->6379/tcp   musing_wescoff

连接测试

用有mysql客户端的登录测试

[root@dev ~]# mysql -uroot -p123456 -h192.168.56.101
Warning: Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or g.
Your MySQL connection id is 20
Server version: 5.6.38 MySQL Community Server (GPL)

Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or 'h' for help. Type 'c' to clear the current input statement.

mysql>

docker caddy 克隆私有仓库遇到的问题

问题描述

我使用的是 gogs 作为自己私有的 git server. 正常的将 .ssh 目录直接导入到了 docker 中. 然后启动 docker 报错如下

Warning: Permanently added the RSA host key for IP address
'xx.xx.xx.xx' to the list of known hosts.

想必经常玩vps的人对这个提示并不陌生.. 我们每次是有 ssh 尝试连接一台我们从没有连接过服务器都会出现, 但是在 docker 中如何避免这个提示?

解决

其实就是要跳过这个验证, 网上一搜基本就能找到. 将 StrictHostKeyChecking 直接配置到 .ssh/config 中 就可以了.

# 文件 .ssh/config
# 以 github.com 为例 自行替换成自己的 git server 地址
Host github.com
    StrictHostKeyChecking no

这样请求的时候就会跳过跳过验证直接 clone 代码了