常用参数表

–where ‘id<3000’ 设置操作条件
–limit 10000 每次取1000行数据给pt-archive处理
–txn-size 1000 设置1000行为一个事务提交一次
–progress 5000 每处理5000行输出一次处理信息
–statistics 结束的时候给出统计信息:开始的时间点,结束的时间点,查询的行数,归档的行数,删除的行数,以及各个阶段消耗的总的时间和比例,便于以此进行优化。只要不加上–quiet,默认情况下pt-archive都会输出执行过程的
–charset=UTF8 指定字符集为UTF8
–no-delete 表示不删除原来的数据,注意:如果不指定此参数,所有处理完成后,都会清理原表中的数据
–bulk-delete 批量删除source上的旧数据
–bulk-insert 批量插入数据到dest主机 (看dest的general log发现它是通过在dest主机上LOAD DATA LOCAL INFILE插入数据的)
–purge 删除source数据库的相关匹配记录
–local 不把optimize或analyze操作写入到binlog里面(防止造成主从延迟巨大)
–analyze=ds 操作结束后,优化表空间(d表示dest,s表示source)
默认情况下,pt-archiver操作结束后,不会对source、dest表执行analyze或optimize操作,因为这种操作费时间,并且需要你提前预估有足够的磁盘空间用于拷贝表。一般建议也是pt-archiver操作结束后,在业务低谷手动执行analyze table用以回收表空间

只删除历史数据

pt-archiver \
--source h=127.0.0.1,P=3306,u=wwek,p='你的密码',D=你的库,t=你的表 \
--charset=UTF8 --where '1=1' --progress 10000 --limit=1000 --txn-size 1000 --bulk-delete --statistics --purge

参考

优雅地使用pt-archiver进行数据归档
pt-archiver手册

介绍

使用Kali Linux需要做一些初始化配置才能用的更顺手

修改apt-get的源为阿里云

vim /etc/apt/sources.list

#deb http://http.kali.org/kali kali-rolling main non-free contrib
deb https://mirrors.aliyun.com/kali kali-rolling main non-free contrib

修改时区

ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
echo 'Asia/Shanghai' >/etc/timezone

输入法fcitx拼音,Sogou输入法

apt-get update && apt-get upgrade
apt-get install fcitx
apt install fcitx-libs fcitx-libs-qt
# 去 https://pinyin.sogou.com/linux/?r=pinyin 下载64位的deb包
dpkg -i sogoupinyin_2.2.0.0108_amd64.deb
# apt-get install fcitx fcitx-googlepinyin fcitx-pinyin fcitx-module-cloudpinyin

虚拟专用网络客户端

apt-get install network-manager-pptp
apt-get install network-manager-strongswan
apt-get install network-manager-vpnc
/etc/init.d/network-manager restart

Kali Linux 安装 zerotier的方法

当kali linux安装zerotier的时候使用

curl -s https://install.zerotier.com/ | sudo bash

并不能安装成功,系统会提示未匹配的系统
其实我们知道kali linux是基于debian定制的,那么把kali的标识加入安装脚本后让其识别为debian系统
这样就可以正常安装了
先下载脚本

curl -s https://install.zerotier.com/ > zerotier.sh
vim zerotier.sh

然后在增加

# 约175行左右
elif [ "$dvers" = "10" -o "$dvers" = "11" -o "$dvers" = "sid" -o "$dvers" = "buster" ]; then
# 改为
elif [ "$dvers" = "10" -o "$dvers" = "11" -o "$dvers" = "sid" -o "$dvers" = "buster"  -o "$dvers" = "kali-rolling" ]; then
# 保持后执行
sudo bash zerotier.sh

即可正常安装

Kali Linux 安装VNC+noVNC并设置开机自动启动

vnc server选择使用
noVNC让vnc可以通过web访问

vnc server

sudo apt-get install vnc4server
# 先要运行一遍vncserver 会提示你设置一个密码 (第二轮的密码是vnc的仅查看密码可以输入N不设置)
vncserver
# 设置密码巴拉巴拉
# 关闭vnc
# vncserver -kill :1

修改vnc的配置(kali linux桌面用的xfce)

vim ~/.vnc/xstartup

#!/bin/bash

export XKL_XMODMAP_DISABLE=1
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS

if [ -e "$HOME/.Xresources" ]
then
    xrdb "$HOME/.Xresources"
fi

startxfce4 &

noVNC

noVNC安装

git clone https://github.com/novnc/noVNC.git /usr/local/noVNC
cd /usr/local/noVNC
nohup ./utils/launch.sh --vnc localhost:5901 &

设置VNC和noVNC开机自动启动

由于debian的新版本已经没有 /etc/rc.local 导致我们不能非常简单方便的增加开机自动运行
还好有系统有预留开启”/etc/rc.local”的方法

vim /etc/rc.local
# 加入vncserver 和 noVNC的启动项目
vim /etc/rc.local
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

#vnc
#/usr/bin/vncserver -depth 24 -geometry 1280x800 :1
/sbin/runuser -l root -c "vncserver :1"
nohup /usr/local/noVNC/utils/launch.sh --vnc localhost:5901 &

exit 0

# 启用 "/etc/rc.local"的支持
systemctl enable rc-local
systemctl start rc-local
systemctl status rc-local

(过期)安装vncserver远程桌面

sudo apt-get install vnc4server

vncserver

#修改配置文件
# vi ~/.vnc/xstartup

#!/bin/sh
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
startxfce4 &

[ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup
[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources
xsetroot -solid grey
vncconfig -iconic &

killall Xtightvnc
vncserver

kali linux安装docker

# step 1: 安装必要的一些系统工具
sudo apt-get update
sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common
# step 2: 安装GPG证书
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/debian/gpg | sudo apt-key add -
# Step 3: 写入软件源信息
vim /etc/apt/sources.list.d/docker.list
deb https://mirrors.aliyun.com/docker-ce/linux/debian wheezy stable
# Step 4: 更新并安装 Docker-CE
sudo apt-get -y update
sudo apt-get -y install docker-ce

Istio能用于生产了么

截止2018年5月6日目前Istio版本号还未达到V1.0,官方也未宣布生产就绪,所以不能用于生产
目前Istio除了不还不完全成熟以外,还有性能问题

当前Feature Status(Road map)

Istio成熟状态 可以在这里查看目前Istio各个组件模块的完善程度

前言

组织的容器支持docker-compose部署
组织的容器支持kubernets部署
以php框架thinkphp为示例,演示php项目的kubernets部署
多容器方式(3容器)分别为:appphp(php代码)、openresty(nginx webserver),php-fpm(php的运行环境)
dockerfile 和 yaml文件
docker iamges仓库

PHP项目在Docker中如何部署运行?

PHP应用的运行方式

PHP应用的运行方式一般有
Apache mod_php 模式、Nginx(FastCgi)+PHP-FPM模式、Swoole常驻内存Daemon模式

Docker单容器

Apache mod_php 模式和Swoole常驻内存Daemon模式本身就是单程序,那么在Docker中入口运行程序直接为应用程序即可

Nginx(FastCgi)+PHP-FPM模式需要nginx和php-fpm 2个程序
这样Docker中就需要运行多个程序,需要有进程守护类软件来运行多个程序,那么可以参考如何在一个Docker中运行多个程序进程
推荐使用s6-overlay

Docker Hub中PHP官方镜像包已经包括Apache mod_php 模式的镜像包,Kubernets官方PHP项目实例GuestBook中就是采用这种模式的镜像包

Docker多容器配合

Docker官方倡导容器单一职责,也就是一个容器只运行一个程序
那么Nginx(FastCgi)+PHP-FPM模式就需要2个容器配合编排工作,再加上如果把PHP代码再独立成一个Docker镜像,那么就是3容器配合编排工作
所以下面就是以PHP项目采用多个Docker镜像的方式再Kubernets平台部署的范例

kubernets(k8s)部署运行

思路说明
容器共有3个,① appphp(wwek/k8s-php-thinkphp-hello:app-v1)php代码容器、② php-fpm(wwek/k8s-php-thinkphp-hello:php-fpm-7.2) 、③ openresty(wwek/k8s-php-thinkphp-hello:openresty)
apphp、php-fpm、openresty三个容器都在一个Pod(8s-php-thinkphp-hello)中
appphp容器作为initContainers初始化容器使用
挂载了一个叫做wwwroot的volume,类型为emptyDir,临时卷
initContainers初始化容器的时候会把php代码复制到wwwroot(volume)中
php-fpm和openresty都挂载wwwroot(volume)
openresty的upstream php 使用域名php-fpm
使用hostAliases把域名php-fpm解析为127.0.0.1(在同一个Pod中网络是共享的,所以用127.0.0.1)

具体的yaml文件

# Service
apiVersion: v1
kind: Service
metadata:
  name: k8s-php-thinkphp-hello
  labels:
    app: k8s-php-thinkphp-hello
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app: k8s-php-thinkphp-hello
---
# deployment
apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: k8s-php-thinkphp-hello
  labels:
    app: k8s-php-thinkphp-hello
spec:
  replicas: 1
  selector:
    matchLabels:
      app: k8s-php-thinkphp-hello
  template:
    metadata:
      labels:
        app: k8s-php-thinkphp-hello
    spec:
    #做一个emptyDir类型,名为wwwroot的volume 用于多个容器共享同一个挂载
      volumes:
      - name: wwwroot
        emptyDir: {}
      # 私有docker 镜像仓库
      # imagePullSecrets:
      # - name: registrykey-qlcoud-1
      # 自定义设置POD的hosts
      hostAliases:
      - ip: "127.0.0.1"
        hostnames:
        - "php-fpm"
      initContainers:
       #php程序本身
        - name: appphp
          image: "wwek/k8s-php-thinkphp-hello:app-v1"
          imagePullPolicy: Always
          # 复制php程序文件到wwwroot volume
          command: ["sh", "-c", "cp -r /var/www/k8s-php-thinkphp-hello /appdata"]
          volumeMounts:
          - mountPath: /appdata
            name: wwwroot
      containers:
       #php-fpm php运行环境
        - name: php-fpm
          image: "wwek/k8s-php-thinkphp-hello:php-fpm-7.2"
          imagePullPolicy: Always
          volumeMounts:
          - mountPath: /var/www
            name: wwwroot
      #openrsty webserver
        - name: openresty
          image: "wwek/k8s-php-thinkphp-hello:openresty"
          imagePullPolicy: Always
          volumeMounts:
          - mountPath: /var/www
            name: wwwroot
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          # livenessProbe:
          #   httpGet:
          #     path: /
          #     port: http
          # readinessProbe:
          #   httpGet:
          #     path: /
          #     port: http
          resources:
            {}
---
# Ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: k8s-php-thinkphp-hello
  labels:
    app: k8s-php-thinkphp-hello
spec:
  rules:
    - host: k8sphpthinkphp.com
      http:
        paths:
          - path: /
            backend:
              serviceName: k8s-php-thinkphp-hello
              servicePort: http
kubectl apply -f k8s-php-thinkphp-hello.yml
kubectl get pods |grep k8s-php-thinkphp-hello
kubectl get service |grep k8s-php-thinkphp-hello
kubectl get ingress |grep k8s-php-thinkphp-hello

把 k8sphpthinkphp.com hosts解析到Ingress 的ip
然后浏览器

访问 http://k8sphpthinkphp.com/ 可以看到thinkphp的欢迎页面

访问 http://k8sphpthinkphp.com/phpinfo.php 可以看到phpinfo信息

如果没有ingress请自行修改service的type为 NodePort 使用节点的ip和端口访问

docker-compose部署运行

一套打包好的业务PHP Docker业务镜像也可以用docker-compose部署,这样方便了本地的开发调试使用

version: '2'

services:

### Applications Code Container #############################

    appphp:
      image: wwek/k8s-php-thinkphp-hello:app-v1
      build:
        context: ./appphp
        dockerfile: "Dockerfile"

### PHP-FPM Container #######################################

    php-fpm:
      image: wwek/k8s-php-thinkphp-hello:php-fpm-7.2
      build:
        context: ./php-fpm
        dockerfile: "Dockerfile"
      volumes_from:
        - appphp
      environment:
        - RUN_MODE=prd
        - MYSQL_HOSTNAME= \
        - MYSQL_USERNAME= \
        - MYSQL_PASSWORD= 
      depends_on:
        - appphp
      expose:
        - "9000"
      networks:
        - backend

### OPENRESTY Server Container ##################################

    openresty:
      image: wwek/k8s-php-thinkphp-hello:openresty
      build:
        context: ./openresty
        dockerfile: "Dockerfile"
      volumes_from:
        - appphp
      ports:
        - "80:80"
        - "443:443"
      depends_on:
        - php-fpm
      networks:
        - frontend
        - backend

### Networks Setup ############################################

networks:
  frontend:
    driver: "bridge"
  backend:
    driver: "bridge"

### Volumes Setup #############################################

volumes:
  redis:
    driver: "local"

直接up方式,直接pull已经build好的docker images

docker-compose up -d

本地build方式

docker-compose up -d --build

浏览器 访问 http://127.0.0.1 访问 http://127.0.0.1/phpinfo.php

代码

所有配置范例代码已经托管到github
k8s-php-thinkphp-hello

PHP在服务化微服务中遇到的问题

项目大了后服务化是必然的!
想象下几十个PHP项目,里面有大多数项目有同样的功能需求,我们可以用复制代码解决
但是对代码维护来说简直是噩梦,一次调整,调整多个项目,简直爽歪歪
先谈服务化拆分,再谈用微服务落地。 做好服务化是目的,用微服务落地是实现方式
那么微服务落地需要一大堆的服务治理能力来支撑,服务注册发现,断路器,网关,RPC等等
微服务中服务注册发现,总不可能手动管理各种服务,那么得有服务注册发现这个东西
由于apache php ,PHP-FPM php不是常驻内存的方式运行,导致了在服务注册发现等方便不能做,服务注册发现又是基础
正因为这个特性让PHP在虚拟主机年代大放异彩,也是因为本身特性导致PHP在服务化,微服务领域落地困难,不过就没解决办法了? 办法是有,但是小公司玩不起来。下面看看市面上的解决方案。

目前用PHP做微服务的解决方案

要用PHP做微服务必须要搞定微服务的服务注册发现问题

Agent模式

微博采用了这样的方式,在跑PHP-FPM的机器上跑了一个Agent(这个和后面会讲到的Service Mesh的 Sidecar模式很像)
通过Agent去完成服务注册发现,调用方通过Agent去调用。Agent作为一个包裹层。
Agent其实是后面在Service Mesh节提到的Sidecar的雏形。

以Swoole为基础的常驻内存damon模式

Swoole是PHP的一个扩展
使 PHP 开发人员可以编写高性能的异步并发 TCP、UDP、Unix Socket、HTTP,WebSocket 服务。Swoole 可以广泛应用于互联网、移动通信、企业软件、云计算、网络游戏、物联网(IOT)、车联网、智能家居等领域。
基于Swoole开发的php程序是直接常驻内存damon的方式运行的
所以这样就可以方便的做服务注册和发现了
基于Swoole体系的开源PHP微服务框架有
Swoft
PHP-MSF
GroupCo
SwooleDistributed
Tencent/Tars

综述PHP微服务落地

综上述
方式1 以微博为代表的Agent代理模式(php-fpm模式运行的php程序因为运行机制问题,导致只有Agent的模式才能做服务注册发现,极少公司有这个技术支撑)
方式2 以Swoole为基石的常驻内存damon模式
生产可用问题,没有广泛的使用经验,目前有部分有强力技术支持的公司在运用,如果要用于自己的环境需要有技术团队去完成这个落地,需要开发一些配套的管控基础设施
毕竟没有服务治理能力贸然上微服务就是自己搞死自己的事

未来PHP做微服务的解决方案

Java体系以 Spring Cloud、Dubbo为代表的微服务框架得到广泛应用的时候无疑是对java编程语言的助推加持
现有的微服务框架不是就完美了,任何事物都是具备两面性的,现有的框架面临SDK更新,业务代码侵入,编程语言绑定(要做非常多的SDK)等诸多问题

Linkerd横空出世,提出了一个叫做Service Mesh的东西中文翻译叫做服务网格
随后以Google Ibm联合起来紧跟着发起了Istio项目
Service Mesh是一个非常新的概念,在2017年才提出,被誉为下一代微服务框架
试图解决现在的微服务框架的诸多问题,最终实现包含现有框架的所有功能,而且还能实现业务代码零侵入

Service Mesh使用了Sidecar模式接管了网络,所以才能实现业务代码零侵入
正因为Service Mesh的这样的架构设计,所以可以真正的实现编程语言无关性,不同服务可以使用不同的编程语言,不需要为不同的语言每个都去维护SDK

那么用PHP做的服务,不论是apache php ,PHP-FPM php, 还是Swoole damon都可以,可以做到真正的语言无关,应用程序本身是不关心微服务那一堆事情的

目前Service Mesh还存在的问题
体系还是非常早期的阶段,以Istio为例,目前大部分特性都是处在Alpha阶段(https://istio.io/about/feature-stages.html)
性能损失问题,据网上看到的测试Istio目前的版本有40%的性能损失(我觉得这个不是重点,只看字面40%,想象下实际业务场景呢? 解决的问题的收益远大于问题,况且后期肯定有优化的空间)
可能需要K8s才能更好的落地,以Istio为例虽然不强制依赖k8s,但是在k8s运行Istio才是最佳选择,使用k8s也是需要学习成本的(我觉得用k8s不是问题,中小公司可以用云平台直接提供的k8s能力,大公司也不用担心没人运维k8s的问题)
Service Mesh到规模落地时间可能还有2年左右的时间

业务代码开发为什么要关注服务治理的东西,微服务的东西? 这就是抽象成一层框架干的事情

作为phper未来还有机会么

诚然PHP在微服务时代被沦为了“前端”语言,写PHP的在大公司沦为“套模板”的。
在Java Spring Cloud 全家桶面前,phper是看着人家的工具库牛逼。
phper是否没机会了呢,php是否没机会了呢
仅仅是从语言角度讲,首先phper当然有机会,php也当然有机会,phper不要局限在php语言本身,js框架vue,Golang都是可以学习的目标
再次市面上还有大量的web站点只需要php就可以快速简单的达成,根本不需要服务化,什么微服务,老夫拿起php连上redis、mysql就是干,单体应用分分钟出活
phper不用担心没出路,php在web领域的优势、市场需求都会验证这一点

需要2年时间,Service Mesh在中大型公司一定会落地,小公司也会在云平台上找到落地的可能,php一样可以干微服务“后端”干的事!