mint 18.2(Sonya)安装docker

与ubuntu安装大体一致,参考官网提供的ubuntu安装方式
官方安装 https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/

安装步骤

1、删除原有版本

sudo apt-get remove docker docker-engine docker.io

2、(推荐略过这一步) 现在docker默认的文件系统为overlay2,如果需要使用aufs(早期docker的文件系统),请执行以下命令

sudo apt-get update
sudo apt-get install 
    linux-image-extra-$(uname -r) 
    linux-image-extra-virtual

3、安装docker ce

docker-ce 是docker的社区版,免费使用,有三种方式安装

  • 添加源,使用apt-get安装
  • 下载deb包,使用dpkg安装
  • 使用提供的脚本安装
    这里选择第一种安装方式

使用apt-get安装

安装需要的工具,

sudo apt-get update
sudo apt-get install 
    apt-transport-https 
    ca-certificates 
    curl 
    software-properties-common

添加认证,

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

根据你的硬件架构选择相应的源进行添加,测试机器为amd64架构,docker支持amd64,armhf,s390x等方式,其余架构添加方式参考官网
下面命令中$(lsb_release -cs)查看系统codename,mint基于ubuntu,使用ubuntu的软件源 ,
所以将

sudo add-apt-repository 
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu 
   $(lsb_release -cs) 
   stable"

替换为 xenial ,执行以下替代命令

sudo add-apt-repository 
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu 
   xenial 
   stable"

更新软件源

sudo apt-get update

测试环境直接安装最新版docker-ce

sudo apt-get install docker-ce

如果是正式环境,可能需要安装指定版本的

sudo apt-get install docker-ce=<VERSION>

如果没有报错,那就大功告成~
跑个hello world

sudo docker run hello-world
Unable to find image ‘hello-world:latest’ locally 
latest: Pulling from library/hello-world 
9a0669468bf7: Pull complete

说明已经获取到官方仓库里的镜像啦~

权限问题

因为安装都是使用sudo即root权限安装,使用的时候,如果没有root权限会提示

Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: 巴拉巴拉

/var/run/docker.sock 作用

它是Docker守护进程(Docker daemon)默认监听的Unix域套接字(Unix domain socket),容器中的进程可以通过它与Docker守护进程进行通信 .
把自己加到docker组

sudo usermod -a -G docker $(whoami)

完全退出当前登录用户,使修改生效

安装docker-compose

docker-compose 是个官方提供管理镜像的工具,对镜像进行一些编排,减化docker使用命令等功能  
官方安装:https://docs.docker.com/compose/install/

下载二进制包,可以直接从github获取,参考下面命令,
其中1.18.0 是截止到文章发布日期的最新版本,具体版本后,点击链接查询

sudo curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

添加执行权限

sudo chmod +x /usr/local/bin/docker-compose

大功告成

docker-compose --version
# docker-compose version 1.18.0, build 8dd22a9

.NET Core容器化之多容器应用部署@Docker-Compose

未分类

1. 引言

紧接上篇.NET Core容器化@Docker,这一节我们先来介绍如何使用Nginx来完成.NET Core应用的反向代理,然后再介绍多容器应用的部署问题。

2. Why Need Nginx

.NET Core中默认的Web Server为Kestrel。

Kestrel is great for serving dynamic content from ASP.NET, however the web serving parts aren’t as feature rich as full-featured servers like IIS, Apache or Nginx. A reverse proxy-server can allow you to offload work like serving static content, caching requests, compressing requests, and SSL termination from the HTTP server.

Kestrel可以很好的用来为ASP.NET提供动态内容,然而在Web服务方面没有IIS、Apache、Nginx这些全功能的服务器完善。我们可以借助一个反向代理服务器接收来自互联网的HTTP请求并在经过一些初步处理(比如请求的缓存和压缩、提供静态内容、SSL Termination)后将其转发给Kestrel。

未分类

未分类

借助反向代理服务器(本文使用Nginx),不仅可以给我们的Web网站提供了一个可选的附加层配置和防御,而且可以简化负载均衡和SSL设置。而更重要的是,反向代理服务器可以很好的与现有的基础设施进行整合。

3. Hello Nginx

同样我们还是基于Docker来试玩一下Nginx。

//拉取Nginx镜像
$ docker pull nginx
//启动Nginx容器
$ docker run -d -p 8080:80 --name hellonginx nginx

上面我们以后台运行的方式启动了一个命名为hellonginx的nginx容器,其端口映射到宿主机的8080端口,我们现在可以通过浏览器直接访问http://:8080即可看到nginx的欢迎界面。

未分类

至此,一个Nginx容器就启动完毕了。那如何进行反向代理呢?别急,我们一步一步来。

4. 反向代理.NET Core MVC

4.1. 启动Web容器

还记得我们上一篇本地打包MVC项目创建的hellodocker.web的镜像吗?这里我们再启动该镜像创建一个容器:

//启动一个helodocker.web的镜像并命名容器为hellodocker.web.nginx
#  docker run -d -p 5000:5000 --name hellodocker.web.nginx hellodocker.web
160166b3556358502a366d1002567972e242f0c8be3a751da0a525f86c124933
//尝试访问刚刚运行的容器
[root@iZ288a3qazlZ ~]# curl -I http://localhost:5000
HTTP/1.1 200 OK
Date: Sun, 24 Dec 2017 02:48:16 GMT
Content-Type: text/html; charset=utf-8
Server: Kestrel
Transfer-Encoding: chunked

OK,我们开放了宿主机的5000端口用来映射我们启动的MVC容器。

4.2. 配置反向代理

下面我们就来配置Nginx来反向代理我们刚启动的Web容器。
要想Nginx成功代理指定的容器内运行的Web网站,首先我们得知道容器对应的IPAddress。使用docker inspect 即可查到。

//查看正在运行的容器列表
$ docker ps 
CONTAINER ID        IMAGE                          COMMAND                  CREATED             STATUS              PORTS                            NAMES
d046b7b878a0        hellodocker.web                "dotnet run"             5 seconds ago       Up 3 seconds        0.0.0.0:5000->5000/tcp           hellodocker.web.nginx

//使用`|`管道操作符加上`grep`过滤操作符可以直接提取我们要查找的关键字
$ docker inspect hellodocker.web.nginx | grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "192.168.0.5",
                    "IPAddress": "192.168.0.5",

从上面可以看到我的Web容器运行在宿主机的192.168.0.5:5000。下面我们配置Nginx转发请求到192.168.0.5:5000即可完成反向代理。

Nginx配置反向代理的配置文件路径为:/etc/nginx/conf.d/default.conf。
我们可以通过本地创建一个配置文件挂载到Nginx的容器内部进行反向代理配置。

$ cd demo
$ mkdir nginx
//创建my_nginx.conf文件
$ touch my_nginx.conf
$ vi my_nginx.conf
server {
  listen 80;

  location / {
    proxy_pass http://192.168.0.5:5000;
  }
}

上面我们通过指定listen配置nginx去监听80端口,指定proxy_pass为我们Web容器的IP和端口完成反向代理文件的配置。
接下来就是启动一个新的Nginx容器并通过挂载的方式将配置文件共享到容器内部。

$ docker run -d -p 8080:80 
> -v $HOME/demo/nginx/my_nginx.conf:/etc/nginx/conf.d/default.conf 
> nginx
95381aa56a336f65b6d01ff9964ae3364f37d25e5080673347c1878b3a5bb514
/usr/bin/docker-current: Error response from daemon: driver failed programming external connectivity on endpoint elated_mccarthy (5a576d5991dd164db69b1c568c94c15e47ec7c67e43a3dd6982a2e9b83b60e08): Bind for 0.0.0.0:8080 failed: port is already allocated.

我们发现容器启动失败,原因是8080端口被我们刚刚第一次启动的nginx容器占用了。怎么办?两个方法:第一种就是将刚才创建的nginx容器干掉;第二种就是映射到新的端口。这里选择第一种。

$ docker ps
1bd630b60019        nginx                          "nginx -g 'daemon off"   59 minutes ago      Up 59 minutes       0.0.0.0:8080->80/tcp             hellonginx
//使用docker rm <container id>删除容器,指定-f进行强制删除
$ docker rm 1bd630b60019 -f
//重新启动Nginx容器
$ docker run -d -p 8080:80 
> -v $HOME/demo/nginx/my_nginx.conf:/etc/nginx/conf.d/default.conf 
> nginx
793d4c62ec8ac4658d75ea0ab4273a0b1f0a9a68f9708d2f85929872888b121d

启动成功后,我们再在浏览器中访问http://:8080,发现返回的不再是Nginx的默认欢迎页,而是我们启动的Web容器中运行的MVC的首页,说明反向代理配置成功!

未分类

5. Docker Compose让一切更简单

上面的步骤虽然简单,但要分两步进行:第一个就是我们的Web和Nginx要分两次部署,第二个就是我们必须知道Web容器的IP和端口号,以完成反向代理文件的配置。

对于需要多个容器(比如需要Nginx、SqlServer、Redis、RabbitMQ等)协调运行的复杂应用中,使用以上方式进行部署时,很显然会很麻烦,而且还要为各个容器之间的网络连接而苦恼。
还好,Docker体贴的为我们想到了这一点。借助Compose模块,我们可以编写一个docker-compose.yml文件,使用声明性语法启动一系列相互连接的容器,即可一步完成上面的任务。

Docker Compose是一个用来定义和运行复杂应用的Docker工具。使用Compose,你可以在一个文件中定义一个多容器应用,然后使用一条命令来启动你的应用,完成一切准备工作。

5.1. 安装Docker Compose

依次执行以下命令:

$ sudo curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
docker-compose version 1.18.0, build 1719ceb

5.2. 编写第一个docker-compose.yml

dockers-compose.yml文件要定义在我们项目的文件夹下,我们的项目文件夹位于$HOME/demo/HelloDocker.Web。

$ cd $HOME/demo/HelloDocker.Web
$ touch docker-compose.yml
$ vi docker-compose.yml
version: '2'
services:
    hellodocker-web:
        container_name: hellodocker.web.compose
        build: .

    reverse-proxy:
        container_name: reverse-proxy
        image: nginx
        ports:
         - "9090:8080"
        volumes:
         - ./proxy.conf:/etc/nginx/conf.d/default.conf

简单介绍下上面的配置文件,其中定义了两个服务:一个是hellodocker-web,即以我们当前项目目录来构建镜像并启动一个叫hellodocker.web.compose的容器。一个是reverse-proxy,用来使用nginx镜像进行反向代理,其中又通过指定volumes来使用挂载的方式进行配置。

$ touch proxy.conf
$ vi proxy.conf
server {
    listen 8080;

    location / {
      proxy_pass http://hellodocker-web:5000;
    }
}
$ ls
[root@iZ288a3qazlZ HelloDocker.Web]# ls
appsettings.Development.json  Controllers             Models      Startup.cs
appsettings.json              docker-compose.yml      obj         Views
bin                           Dockerfile              Program.cs  wwwroot
bundleconfig.json             HelloDocker.Web.csproj  proxy.conf
[root@iZ288a3qazlZ HelloDocker.Web]#

其中要注意反向代理的配置:proxy_pass http://hellodocker-web:5000;,其中ip部分直接指定的是docker-compose.yml中定义的第一个服务的名称hellodocker-web。
下面我们就来启动Compose:

$ docker-compose up -d
Building hellodocker-web
Step 1 : FROM microsoft/dotnet:latest
 ---> 7d4dc5c258eb
Step 2 : WORKDIR /app
 ---> Using cache
 ---> 98d48a4e278c
Step 3 : COPY . /app
 ---> 0cb9fc540afe
Removing intermediate container 9fecf088f03f
Step 4 : RUN dotnet restore
 ---> Running in 4bb7f34edbbe
  Restore completed in 597.13 ms for /app/HelloDocker.Web.csproj.
  Restoring packages for /app/HelloDocker.Web.csproj...
  Restore completed in 1.76 sec for /app/HelloDocker.Web.csproj.
 ---> 6869609ece23
Removing intermediate container 4bb7f34edbbe
Step 5 : EXPOSE 5000
 ---> Running in a97febf01e5a
 ---> 9b2639862a94
Removing intermediate container a97febf01e5a
Step 6 : ENV ASPNETCORE_URLS http://*:5000
 ---> Running in 4e2f4af28a8d
 ---> 0069661e891a
Removing intermediate container 4e2f4af28a8d
Step 7 : ENTRYPOINT dotnet run
 ---> Running in cbbf08d906f9
 ---> 0bbeef249b30
Removing intermediate container cbbf08d906f9
Successfully built 0bbeef249b30
WARNING: Image for service hellodocker-web was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating hellodocker.web.compose ... done
Starting reverse-proxy ... done
//执行docker-compose ps验证启动的服务
$ docker-compose ps
         Name                   Command          State               Ports
---------------------------------------------------------------------------------------
hellodocker.web.compose   dotnet run             Up      5000/tcp
reverse-proxy             nginx -g daemon off;   Up      80/tcp, 0.0.0.0:9090->8080/tcp
//使用curl指令验证nginx的反向代理
$  curl -I http://localhost:9090
HTTP/1.1 200 OK
Server: nginx/1.13.7
Date: Sun, 24 Dec 2017 04:37:35 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive

可以看到,通过执行curl -I http://localhost:9090验证代理服务器配置成功,我们再通过浏览器访问http://:9090发现正确返回了我们MVC项目的默认首页。

// 查看当前运行的容器
$ docker ps
CONTAINER ID        IMAGE                            COMMAND                  CREATED             STATUS              PORTS                            NAMES
a52830499cff        hellodockerweb_hellodocker-web   "dotnet run"             7 minutes ago       Up 7 minutes        5000/tcp                         hellodocker.web.compose
e1fe109e10bc        nginx                            "nginx -g 'daemon off"   11 minutes ago      Up 4 minutes        80/tcp, 0.0.0.0:9090->8080/tcp   reverse-proxy

我们同时也发现通过docker-compose正确的创建了两个容器hellodocker.web.compose和reverse-proxy。

6. 最后

经过以上的练习,我们对Nginx有了一定的了解,且知道如何进行配置。同时了解了如何借助docker-compose打包运行需要多容器的复杂应用。

Docker下实战zabbix三部曲之三:自定义监控项

通过上一章《Docker下实战zabbix三部曲之二:监控其他机器》的实战,我们了解了对机器的监控是通过在机器上安装zabbix agent来完成的,zabbix agent连接上zabbix server之后,将自己所在机器的信息定时给到zabbix server,这样就实现了机器的监控;
但是我们能监控到的只有cpu,磁盘这些基础信息,对于一些业务信息例如访问量,某个逻辑的执行成功失败次数等信息,我们也想进行监控,这就需要我们去制作自定义监控项了,本章我们就一起来实战自定义监控项吧。

机器部署情况一览

总的来说,有四台机器,各自的功能如下:
a. 假设有一个机器在运行web应用,容器是tomcat,这个应用有个接口http://localhost:8080/zabbixcustomitemdemo/count,可以返回最近一分钟的某个业务量(例如网站访问次数);

b. 有一台机器安装了zabbix agent,作为自定义监控项的载体;
c. 有一台机器安装了zabbix server;
d. 有一台机器安装了mysql,作为zabbix系统的数据库;

整体部署如下图所示:

未分类

运行web应用的server

这是个基于maven的java web应用,里面有个spring mvc的controller,提供一个http服务,范围某个业务每分钟的业务量,代码如下图所示:

@Controller
public class CountController {

    @RequestMapping("/count")
    @ResponseBody
    public int count(String model, String type) {
        int base;
        int max;
        int min;

        if("a".equals(model)){
            base = 50000;
        }else{
            base =10000;
        }

        if("0".equals(type)){
            max = 9000;
            min = 1000;
        }else{
            max = 1000;
            min = 0;
        }

        return base + new Random().nextInt(max)%(max-min+1);
    }
}

从以上代码我们可以看出,http服务会返回随机数,此服务接受两个参数model和type,当model等于”a”时返回的随机数从50000开始,model不等于”a”时返回的随机数从10000开始,当type等于”0”时,在base的基础上增加的值是1000到9000之间,当type不等于”0”时,在base的基础上增加的值是0到1000之间;

整个工程的代码已经上传到git上,地址是[email protected]:zq2599/blog_demos.git,这个目录下由多个工程,本次实战的工程是zabbixcustomitemdemo,如下图:

未分类

docker-compose.yml文件

上面我们已经把四台机器的功能和关系梳理清楚了,现在就来制定docker-compose.yml文件吧:

version: '2'
services:
  zabbix-mysql-service: 
    image: daocloud.io/library/mysql:8
    container_name: zabbix-mysql-service
    environment:
      - MYSQL_ROOT_PASSWORD=888888
    restart: always
  zabbix-server-service:
    image: monitoringartist/zabbix-xxl:3.2.6
    links: 
      - zabbix-mysql-service:mysqlhost
    container_name: zabbix-server-service
    restart: always
    depends_on:
      - zabbix-mysql-service
    ports:
      - "8888:80"
    environment:
      - ZS_DBHost=mysqlhost
      - ZS_DBUser=root
      - ZS_DBPassword=888888
  zabbix-agent-a:
    image: zabbix/zabbix-agent:ubuntu-3.2.6
    links: 
      - zabbix-server-service:zabbixserverhost
    container_name: zabbix-agent-a
    restart: always
    depends_on:
      - zabbix-server-service
    environment:
      - ZBX_HOSTNAME=zabbix-agent-service-a
      - ZBX_SERVER_HOST=zabbixserverhost
  tomcat-server-service:
    image: bolingcavalry/bolingcavalrytomcat:0.0.1
    container_name: tomcat-server
    restart: always
    ports:
      - "8080:8080"

yml文件的内容如上所示,其中mysql、zabbix server,zabbix agent的配置和上一章《Docker下实战zabbix三部曲之二:监控其他机器》是一样的,新增的是一个tomcat的镜像,这个镜像是我在tomcat官方镜像的基础上做了点小改动,使得这个tomcat支持在线部署web应用,关于tomcat在线部署应用,请看文章《实战docker,编写Dockerfile定制tomcat镜像,实现web应用在线部署》

准备好yml文件之后,打开终端,在yml文件所在目录下执行docker-compose up -d可以将yml文件中所有的容器都启动;

注意,如果您的电脑之前已经运行过上一章《Docker下实战zabbix三部曲之二:监控其他机器》中的docker-compose.yml文件,那么本次执行docker-compose up -d会提示启动失败,已有同样名称的容器存在,这时候可以去上一章的docker-compose.yml文件所在目录执行docker-compose down,也可以通过docker ps -a将所有容器列出,再通过docker stop命令依次停止所有容器,再执行docker-compose rm命令依次删除;

部署web应用

打开终端,进入web工程zabbixcustomitemdemo的目录下,执行命令mvn clean package -U -Dmaven.test.skip=true tomcat7:redeploy,即可将web工程部署到tomcat容器上,关于在线部署的细节请参照文章《实战docker,编写Dockerfile定制tomcat镜像,实现web应用在线部署》;

部署成功后,打开浏览器,访问http://localhost:8080/zabbixcustomitemdemo/count,web server会返回一个数字,如下图所示:

未分类

制作访问url的shell脚本

接下来我们要在zabbix agent上做一个shell脚本,此脚本的功能时发起http请求http://localhost:8080/zabbixcustomitemdemo/count?model=a&type=0,就能得到web服务响应的数字,如果此脚本每分钟被调用一次,就能得到完整的监控曲线图了;

a. 首先,执行docker exec -it zabbix-agent-a /bin/bash登录zabbix agent的容器;
b. 登录后,执行apt-get update更新apt;
c. 先后执行apt-get install wget和apt-get install vim,安装wget和vi工具;
d. 新建目录/usr/work/,在此目录下用vi创建一个shell文件biz_count.sh,内容如下:

#"!/bin/bash
wget -qO- http://tomcathost:8080/zabbixcustomitemdemo/count?model=$1&type=$2
echo ""

上面代码的功能是访问http服务获取一个数字,其中model和type用的是shell的入参;
注意两个细节:
第一个:最后一行代码echo “”,实践证明这一行是很有用的,有了这一行就会在输出http返回的数字后进行换行,有了换行数据才能成功上报到zabbix server;
第二个:wget命令后面的url参数中,”&”符号前面要加转义的斜杠””;

e. 执行chmod a+x biz_count.sh,给shell赋予可执行权限;

agent上添加监控项

继续在zabbix agent容器上,我们要添加一个自定义监控项,这样后面在zabbix server上就能使用该监控项了:
a. 在/etc/zabbix/zabbix_agentd.d目录下,新增一个biz.conf文件,内容如下:

UserParameter=get_total_num[*],/usr/work/biz_count.sh $1 $2

以上代码配置了一个自定义监控项,名称是get_total_num,可以接受两个入参,该监控项会调用biz_count.sh这个脚本,并且把外部传来的两个入参直接传递给biz_count.sh;

b. 执行chmod a+r biz.conf使得该文件可读;

在zabbix agent上测试

继续在zabbix agent容器上,执行以下命令来测试刚刚新加的监控项:

/usr/sbin/zabbix_agentd -t get_total_num[a,0]

中括号中的a,0表示两个入参分别是”a”和”0”,我们执行四次,入参分别用[a,0]、[b,0]、[a,1]、[b,1],得到的结果如下图所示:

未分类

四个返回值分别是54741、17097、50564、10919,结合前面的java代码可以发现两个参数都生效了,数字的大小范围因入参而变化;

为了让监控项生效,需要重启zabbix agent,不过这里有个更快捷的方法可以试试:
a. 执行exit退出zabbix agent容器;
b. 执行docker restart zabbix-agent-a重启zambia agent容器;

到了这里,自定义监控项已经准备好了,接下来在zabbix server上把它配置成功,我们就能看到监控数据和曲线图了,不过在配置前,我们可以在zabbix server上测试一下能否成功调用zabbix agent上的监控项;

在zabbix server上测试agent机器的监控项

首先我们要搞清楚zabbix agent机器的ip,有两种方法:
第一种,执行docker exec -it zabbix-agent-a /bin/bash登录zabbix agent的容器,在容器中执行ip addr命令可以得到ip;
第二种,直接执行docker exec -it zabbix-agent-a ip addr命令得到ip;

不论哪种,都能得到zabbix-agent的ip是172.31.0.5;

现在我们登录zabbix server容器,执行命令docker exec -it zabbix-server-service /bin/bash即可登录,登录后执行以下命令:

zabbix_get -s 172.31.0.5 -k get_total_num[a,0]

如下图所示,测试成功,调用agent的监控项返回了符合预期的数据:

未分类

还记得我们刚才在zabbix agent上配置好之后,需要重启agent服务或者重启zabbix agent容器,如果您忘了这一步,现在zabbix server上测试会得到如下错误提示:

未分类

这时候去重启一下,再回来测试就可以成功了。

在管理页面上添加监控项

在浏览器上输入”http://localhost:8888/“登录管理页面,先添加agent机器,如下图:

未分类

添加之后,点击下图红框位置,进入监控项页面:

未分类

如下图,点击右上角的“Create item”即可开始添加监控项:

未分类

新增的监控项,我们只要填写Name,Key,Update interval(更新频率)这几个字段,其他的保持不变,每个要更新的字段的内容如下图:

未分类

填写并保存后,我们可以在Monitoring -> Latest data中看到最新的监控项数据,如下图:

未分类

接下来我们添加一个监控图形,操作如下图所示,可以进入图形管理页面:

未分类

如下图,点击右上角的“Create graph”创建一个图形:

未分类

新建图形的时候,名称随意,只要Items选中刚刚创建的监控项即可,如下图:

未分类

创建成功,现在要看看效果了,操作如下图所示:

未分类

点击”add”之后,在弹出的页面上选择刚刚我们新建的图形选项,操作完毕后,点击下图红框位置,就能看见曲线图了:

未分类

曲线图如下:

未分类

以上就是自定义监控项开发和设置的所有过程,基于监控项的操作,除了图形还能添加tirgger用来告警,在添加action用来确定告警的动作,例如邮件短信的,有兴趣的读者可以实际操作实战。

Docker下实战zabbix三部曲之二:监控其他机器

在上一章《Docker下实战zabbix三部曲之一:极速体验》中,我们快速安装了zabbix server,并登录管理页面查看了zabbix server所在机器的监控信息,但是在实际场景中,应该是对应用服务器做监控,所以今天我们来实战将应用服务器的监控加入到zabbix server中。

部署情况

假设实际项目中我们有两台应用服务器,为了监控它们,我们要在上面分别安装zabbix-agent服务,然后通过配置让它们与zabbix server连接,所有监控数据和监控配置数据都被zabbix server保存在mysql中,部署情况如下图:

未分类

真实场景中是在应用服务器上安装zabbix agent服务,但是安装agent的过程和步骤不是本次实践的重点,为了快速体验服务本文使用了zabbix官方的agent镜像,这个镜像实际上就是在ubuntu14上安装了zabbix agent(在服务器上安装zabbix agent的过程就不在本文中详述了,对安装有兴趣的读者们可以去网上搜索相关资料)

docker-compose.yml文件

按照前面图片所示的部署情况,我们的docker-compose.yml内容如下,mysql和zabbix server是必须的,再新增了两个zabbix agent容器,名称分别是zabbix-agent-a和zabbix-agent-b:

version: '2'
services:
  zabbix-mysql-service: 
    image: daocloud.io/library/mysql:8
    container_name: zabbix-mysql-service
    environment:
      - MYSQL_ROOT_PASSWORD=888888
    restart: always
  zabbix-server-service:
    image: monitoringartist/zabbix-xxl:3.2.6
    links: 
      - zabbix-mysql-service:mysqlhost
    container_name: zabbix-server-service
    restart: always
    depends_on:
      - zabbix-mysql-service
    ports:
      - "8888:80"
    environment:
      - ZS_DBHost=mysqlhost
      - ZS_DBUser=root
      - ZS_DBPassword=888888
  zabbix-agent-a:
    image: zabbix/zabbix-agent:ubuntu-3.2.6
    links: 
      - zabbix-server-service:zabbixserverhost
    container_name: zabbix-agent-a
    restart: always
    depends_on:
      - zabbix-server-service
    environment:
      - ZBX_HOSTNAME=zabbix-agent-service-a
      - ZBX_SERVER_HOST=zabbixserverhost
  zabbix-agent-b:
    image: zabbix/zabbix-agent:ubuntu-3.2.6
    links: 
      - zabbix-server-service:zabbixserverhost
    container_name: zabbix-agent-b
    restart: always
    depends_on:
      - zabbix-server-service
    environment:
      - ZBX_HOSTNAME=zabbix-agent-service-b
      - ZBX_SERVER_HOST=zabbixserverhost

如上所示,zabbix agent在配置过程中要用到zabbix server的ip信息,这里我们通过links参数,在zabbix agent的host文件中加入了zabbix server的ip信息,host name是zabbixserverhost;

另外,ZBX_HOSTNAME和ZBX_SERVER_HOST这两个环境变量,在zabbix agent镜像的官方文档中已经说明,如下图,ZBX_HOSTNAME用来表示自己的身份,ZBX_SERVER_HOST是用来标明zabbix server的ip信息的,这里直接用link参数中的alias来表示,就能通过host直接找到zabbix server的ip了:

未分类

启动docker 容器

打开控制台,在docker-compose.yml文件所在的目录下执行命令docker-compose up -d,如图:

未分类

进入控制台

等待大约1分钟,让zabbix server完成初始化,然后就能登录管理页面了,详情请参照《Docker下实战zabbix三部曲之一:极速体验》一文,登录后进入hosts页面,如下图:

未分类

获取监控机器ip

按照前面的部署描述图上的部署,有两台机器装了zabbix agent服务,然后想要加入监控,第一步我们要把机器的ip确定下来,在控制台执行docker exec -it zabbix-agent-a ip addr命令,可以看到如下输出,第一台机器的ip是172.31.0.4:

未分类

在控制台执行docker exec -it zabbix-agent-b ip addr命令,可以看到如第二台机器的ip是172.31.0.5;

添加机器监控

点击hosts页面右上角的Create host按钮,可以添加监控机器,如下图:

未分类

在添加机器的页面,主要参数填写如下:
a. Host name :机器的环境变量ZBX_HOSTNAME的值:zabbix-agent-service-a;
b. Visible name :和Host name的值相同;
c. Groups : 机器分组,这里选择Linux servers;
d. Agent interfaces:这里面只需要填写IP address,就是刚才我们通过命令docker exec -it zabbix-agent-a ip addr得到的ip:172.31.0.4;
这个页面只需要填写以上四点内容,其他的都保持默认值,填写完毕后点击底部的”Add”按钮,如下图:

未分类

增加成功后,在列表中可以看到新增的机器,如下图:

未分类

添加监控项

在机器列表页面中,点击机器名称,如下图红框中位置:

未分类

在打开的页面点击”Templates”,如下图红框所示:

未分类

再点击”Select”按钮,如下图红框所示:

未分类

在弹出的页面中,勾选“Template OS Linux”,然后再点击底部的“Select”按钮,这样就把linux服务的常用监控项给批量添加了,如下图:

未分类

注意,返回的页面中,一定要点击“Add”才能让把刚才的选择加上,如下图:

未分类

然后点击“Update”,完成监控项的批量添加,如下图:

未分类

按照同样的方法把另一台机器的监控也加上;

等待大约1-2分钟后,再刷新hosts页面,就能看到列表中的”ZBX”图标已经变为绿色,表示监控已经生效;

查看监控信息

我们来看看监控曲线图吧,点击下图红框中的“Graphs”:

未分类

可以看到有5个曲线图可以查看,如下图,我们看一下cpu load:

未分类

在跳转的页面中,点击“Previdew”,就能看到cpu load的曲线图了,如下图:

未分类

至此,我们添加监控机器的实战已经完成了,但是在真实场景中,我们除了cpu、磁盘等基础信息的监控,还要监控一些业务有关的数据,例如某个http服务每分钟的访问量,在下一章中,我们一起实战开发一个自定义监控。

Docker下实战zabbix三部曲之一:极速体验

对于想学习和实践zabbix的读者来说,在真实环境搭建一套zabbix系统是件费时费力的事情,本文内容就是用docker来缩减搭建时间,目标是让读者们尽快投入zabbix系统的体验和实践;

创建docker-compose.yml文件

首先创建一份docker-compose.yml文件,内容如下:

version: '2'
services:
  zabbix-mysql: 
    image: daocloud.io/library/mysql:8
    container_name: zabbix-mysql
    environment:
      - MYSQL_ROOT_PASSWORD=888888
    restart: always
  zabbix-server:
    image: monitoringartist/zabbix-xxl
    links: 
      - zabbix-mysql:mysqlhost
    container_name: zabbix-server
    restart: always
    depends_on:
      - zabbix-mysql
    ports:
      - "8888:80"
    environment:
      - ZS_DBHost=mysqlhost
      - ZS_DBUser=root
      - ZS_DBPassword=888888

创建容器

打开命令行,在刚才创建的docker-compose.yml目录下,执行docker-compose up -d,这样就会先后启动mysql和zabbix server两个服务的容器,如下图:

未分类

等待zabbix server初始化

在命令行输入命令docker logs -f zabbix-server-service,查看zabbix server的日志输出,下图是部分日志的截图,可以看到有数据库初始化的操作:

未分类

登录zabbix管理页面体验

等待大约一分钟之后,zabbix server的日志不再滚动,表示初始化已经完成,打开浏览器输入http://localhost:8888,可以看到zabbix的管理系统的登录页面,如下图:

未分类

输入用户名admin,密码zabbix

登录后即可看到管理系统了,如下图:

未分类

按照下图的操作,查看已经监控的主机情况,如图,目前只能看到一台机器的信息,就是zabbix server自己这台机器,从列表的几列信息中可以看到有64个监控项,43个触发器,10个图形:

未分类

上图右侧的红框中显示的status是”Disabled”,表示这个host的监控还没有启动,点击这个”Disabled”就能启动监控,将状态变为”Enabled”,大约1分钟后再刷新页面,可以看到展示如下图:

未分类

除了状态变为”Enabled”,右侧原本灰色的”ZBX”也变成了绿色,表示该机器的监控状态是正常的;

体验监控图形

按照下图的红框和箭头操作,可以看到zabbix server所在机器的cpu load的曲线图:

未分类

显示中文

按照下图的箭头依次点击红框中的内容:

未分类

在打开后的页面中按照下图的箭头依次选择和点击:

未分类

这时候再点击右上角的”注销”按钮,退出重现登录,如下图红框所示:

未分类

再重新登录后,就能看见页面已经全部中文显示了,如下图:

未分类

以上就是Docker下实战zabbix的第一部分,快速体验zabbix系统和服务,但只有一个zabbix server服务器意义不大,毕竟实际场景是要通过zabbix系统去监控其他机器和服务,下一章我们尝试把zabbix agent加入进来,以更接近实际场景的方式来继续学习zabbix。

Docker 搭建 WordPress博客

作为一个docker初学者,几乎第一个案例都是docker轻松搭建一个WordPress,关于WordPress是什么,用来做什么,建议自行百度,下面直接讲解搭建步骤:

使用的ubuntu16.04,每次都要加sudo,我索性直接使用root用户操作。

1、下载MySQL镜像,使用docker命令:docker pull mysql ,我下载的有400多M还是有点慢,需要耐心等待

MySQL下载完毕

2、启动MySQL镜像

docker run --name mysql_db -e MYSQL_ROOT_PASSWORD=123456 -d mysql

取个名字叫mysql_db 密码123456 最后的mysql是告诉docker容器启动一个mysql的数据库。

3、可以通过 docker ps来查看运行的容器

还可以通过 docker inspect id来查看具体信息,ID可以不用输全,只要唯一即可。

4、下载WordPress镜像

docker pull wordpress

5、启动Wordpress

docker run --name wordpressTest --link mysql_db:mysql -p 8086:80 wordpress

ocker run --name wordpressTest --link mysql_db:mysql -p 8086:80 wordpress

给运行的WordPress取个名字叫wordpressTest 数据库link到mysql_db的mysql数据库,端口由默认的80转换到8086,wordpress

6、移除运行的容器,按名字移除

docker rm 名字

7、访问

我是通过虚拟机来进行访问,需要把虚拟机的防火墙进行设置,否则访问不到,我这里直接停止了防火墙服务
Redhat停止防火墙:service iptables stop
Ubuntu停止防火墙:ufw disable
如果启动成功,直接访问http://ip:端口/容器名字 即可访问,
第一次访问需要设置语言、设置登录用户名和密码,由于忘记了截图,请见谅
后面访问

好了,docker运行WordPress到此就搭建完毕。只需要运行docker命令既可,如果按照传统的搭建方式,需要按照各种软件和环境,还有可能每个环境不一样,出现各种奇葩问题,有了docker就不会出现这样的问题。
至于在Linux怎么按照docker,在这里提供ubuntu的按照命令,由于docker是诞生在ubuntu的环境下,建议学习就用ubuntu环境,我在这里就介绍一种自带的按照方式
sudo apt-get update
sudo apt-get install docker.io
这种安装方式需要时ubuntu14.04及以上版本,之前没有自带docker。
docker在Windows和Mac环境没有支持,但是提供了一个docker tool的安装方式,其实也是在Windows和Mac下虚拟了一个Linux环境,网上的建议是安装双系统,没有那个条件,建议还是用虚拟机吧。

docker搭建nginx+php-fpm开发环境

一、创建目录

mkdir -p /data1/www/app;
mkdir -p /data1/www/logs;
mkdir -p /data1/www/php;
mkdir -p /data1/www/nginx;
mkdir -p /data1/www/php/fpm.d;
mkdir -p /data1/www/nginx/vhost;
chmod 777 -R /data1/www;

添加项目:

vim /data1/www/app/www.mydemo.com/index.php
<?php
    echo 22;
    phpinfo();

二、启动容器

docker run -it --name=web_container --net=host -v /data1:/data1 centos /bin/bash;
yum -y install wget;
yum -y install initscripts;

三、安装nginx

依赖说明:

  • zlib: Nginx提供gzip模块,需要zlib库支持。
  • openssl: Nginx提供SSL功能
  • pcre: 支持地址重写rewrite功能

依赖安装:

yum -y install zlib zlib-devel openssl openssl-devel pcre-devel;

依赖检测:

rpm -qa  zlib;
rpm -qa  openssl;
rmp -qa  pcre;

nginx安装

wget http://nginx.org/download/nginx-1.10.3.tar.gz
tar -zxvf nginx-1.10.3.tar.gz;
cd nginx-1.10.3;
./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_flv_module;
make && make install;

创建用户

groupadd  www
useradd -r -g www  www

在宿主机上修改添加配置文件: vim /data1/www/nginx/mime.types

types {
    text/html                             html htm shtml;
    text/css                              css;
    text/xml                              xml;
    image/gif                             gif;
    image/jpeg                            jpeg jpg;
    application/javascript                js;
    application/atom+xml                  atom;
    application/rss+xml                   rss;

    text/mathml                           mml;
    text/plain                            txt;
    text/vnd.sun.j2me.app-descriptor      jad;
    text/vnd.wap.wml                      wml;
    text/x-component                      htc;

    image/png                             png;
    image/tiff                            tif tiff;
    image/vnd.wap.wbmp                    wbmp;
    image/x-icon                          ico;
    image/x-jng                           jng;
    image/x-ms-bmp                        bmp;
    image/svg+xml                         svg svgz;
    image/webp                            webp;

    application/font-woff                 woff;
    application/java-archive              jar war ear;
    application/json                      json;
    application/mac-binhex40              hqx;
    application/msword                    doc;
    application/pdf                       pdf;
    application/postscript                ps eps ai;
    application/rtf                       rtf;
    application/vnd.apple.mpegurl         m3u8;
    application/vnd.ms-excel              xls;
    application/vnd.ms-fontobject         eot;
    application/vnd.ms-powerpoint         ppt;
    application/vnd.wap.wmlc              wmlc;
    application/vnd.google-earth.kml+xml  kml;
    application/vnd.google-earth.kmz      kmz;
    application/x-7z-compressed           7z;
    application/x-cocoa                   cco;
    application/x-java-archive-diff       jardiff;
    application/x-java-jnlp-file          jnlp;
    application/x-makeself                run;
    application/x-perl                    pl pm;
    application/x-pilot                   prc pdb;
    application/x-rar-compressed          rar;
    application/x-redhat-package-manager  rpm;
    application/x-sea                     sea;
    application/x-shockwave-flash         swf;
    application/x-stuffit                 sit;
    application/x-tcl                     tcl tk;
    application/x-x509-ca-cert            der pem crt;
    application/x-xpinstall               xpi;
    application/xhtml+xml                 xhtml;
    application/xspf+xml                  xspf;
    application/zip                       zip;

    application/octet-stream              bin exe dll;
    application/octet-stream              deb;
    application/octet-stream              dmg;
    application/octet-stream              iso img;
    application/octet-stream              msi msp msm;

    application/vnd.openxmlformats-officedocument.wordprocessingml.document    docx;
    application/vnd.openxmlformats-officedocument.spreadsheetml.sheet          xlsx;
    application/vnd.openxmlformats-officedocument.presentationml.presentation  pptx;

    audio/midi                            mid midi kar;
    audio/mpeg                            mp3;
    audio/ogg                             ogg;
    audio/x-m4a                           m4a;
    audio/x-realaudio                     ra;

    video/3gpp                            3gpp 3gp;
    video/mp2t                            ts;
    video/mp4                             mp4;
    video/mpeg                            mpeg mpg;
    video/quicktime                       mov;
    video/webm                            webm;
    video/x-flv                           flv;
    video/x-m4v                           m4v;
    video/x-mng                           mng;
    video/x-ms-asf                        asx asf;
    video/x-ms-wmv                        wmv;
    video/x-msvideo                       avi;
}

新增fast_cig: vim /data1/www/nginx/fastcgi_params

fastcgi_param  QUERY_STRING       $query_string;
fastcgi_param  REQUEST_METHOD     $request_method;
fastcgi_param  CONTENT_TYPE       $content_type;
fastcgi_param  CONTENT_LENGTH     $content_length;

fastcgi_param  SCRIPT_NAME        $fastcgi_script_name;
fastcgi_param  REQUEST_URI        $request_uri;
fastcgi_param  DOCUMENT_URI       $document_uri;
fastcgi_param  DOCUMENT_ROOT      $document_root;
fastcgi_param  SERVER_PROTOCOL    $server_protocol;
fastcgi_param  REQUEST_SCHEME     $scheme;
fastcgi_param  HTTPS              $https if_not_empty;

fastcgi_param  GATEWAY_INTERFACE  CGI/1.1;
fastcgi_param  SERVER_SOFTWARE    nginx/$nginx_version;

fastcgi_param  REMOTE_ADDR        $remote_addr;
fastcgi_param  REMOTE_PORT        $remote_port;
fastcgi_param  SERVER_ADDR        $server_addr;
fastcgi_param  SERVER_PORT        $server_port;
fastcgi_param  SERVER_NAME        $server_name;

# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param  REDIRECT_STATUS    200;

vim /data1/www/nginx/nginx.conf

user  www;
worker_processes  5;

error_log  logs/nginx-error.log;
pid        nginx/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    client_body_temp_path /tmp/client_body_temp_path;
    fastcgi_temp_path /tmp/fastcgi_temp_path;
    proxy_temp_path /tmp/proxy_temp_path;
    scgi_temp_path /tmp/scgi_temp;
    uwsgi_temp_path /tmp/uwsgi_temp_path;

    sendfile        on;
    keepalive_timeout  65;
    gzip  on;
    include vhost/*.conf;
}

配置文件检测

/usr/local/nginx/sbin/nginx -c /data1/www/nginx/nginx.conf -p /data1/www -t

新增项目配置: vim /data1/www/nginx/vhost/mydemo.com.conf

server {
         listen       80 ;
         root /data1/www/app/www.mydemo.com/;
         server_name  www.mydemo.com mydemo.com;

         access_log   logs/nginx_www.mydemo.com-access_log  main;
         error_log    logs/nginx_www.mydemo.com-error_log;
         rewrite  "^/(.*)" /index.php/$1 last;

         location  / {
                   proxy_ignore_client_abort on;
                   fastcgi_pass 127.0.0.1:9023;
                   fastcgi_index index.php;
                   fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                   #fastcgi_param  SCRIPT_URL         $script_uri;
                   #fastcgi_param  REQUEST_ID           $request_uid;
                   include fastcgi_params;
         }
}

启动nginx:

/usr/local/nginx/sbin/nginx -c /data1/www/nginx/nginx.conf -p /data1/www

平滑重启

Kill -HUP  ${nginx_pid}

四、安装php-fpm

yum -y install gd-devel zlib-devel libjpeg-devel libpng-devel libiconv-devel freetype-devel libxml2 libxml2-devel openssl openssl-devel curl-devel libxslt-devel libmcrypt-devel mhash mcrypt
wget http://am1.php.net/get/php-7.2.0.tar.bz2/from/this/mirror ;
tar -jxvf mirror;
cd php-7.2.0;
./configure  --prefix=/usr/local/php --enable-fpm --enable-cli --enable-pcntl --with-curl;
make && make install; 

新增配置文件: vim /data1/www/php/php-fpm.conf

[global]
pid = php/php-fpm.pid
error_log = logs/php-fpm.log
emergency_restart_threshold = 20
emergency_restart_interval = 60s
process_control_timeout = 0
process.max = 2048
daemonize = yes
rlimit_files = 65535
rlimit_core = 67108864
events.mechanism = epoll

; auto include phpfpm configure
include = php/fpm.d/*.conf

vim /data1/www/php/php.ini

[PHP]
engine = On
short_open_tag = Off
precision = 14
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
unserialize_callback_func =
serialize_precision = -1
disable_functions =
disable_classes =
zend.enable_gc = On
expose_php = On
max_execution_time = 30
max_input_time = 60
memory_limit = 128M
error_reporting = E_ALL
display_errors = On
display_startup_errors = On
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
html_errors = On
variables_order = "GPCS"
request_order = "GP"
register_argc_argv = Off
auto_globals_jit = On
post_max_size = 8M
auto_prepend_file =
auto_append_file =
default_mimetype = "text/html"
default_charset = "UTF-8"
doc_root =
user_dir =
enable_dl = Off
file_uploads = On
upload_max_filesize = 2M
max_file_uploads = 20
allow_url_fopen = On
allow_url_include = Off
default_socket_timeout = 60
[CLI Server]
cli_server.color = On
[Date]
[filter]
[iconv]
[intl]
[sqlite3]
[Pcre]
[Pdo]
[Pdo_mysql]
pdo_mysql.cache_size = 2000
pdo_mysql.default_socket=
[Phar]
[mail function]
SMTP = localhost
smtp_port = 25
mail.add_x_header = On
[ODBC]
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultlrl = 4096
odbc.defaultbinmode = 1
[Interbase]
ibase.allow_persistent = 1
ibase.max_persistent = -1
ibase.max_links = -1
ibase.timestampformat = "%Y-%m-%d %H:%M:%S"
ibase.dateformat = "%Y-%m-%d"
ibase.timeformat = "%H:%M:%S"
[MySQLi]
mysqli.max_persistent = -1
mysqli.allow_persistent = On
mysqli.max_links = -1
mysqli.cache_size = 2000
mysqli.default_port = 3306
mysqli.default_socket =
mysqli.default_host =
mysqli.default_user =
mysqli.default_pw =
mysqli.reconnect = Off
[mysqlnd]
mysqlnd.collect_statistics = On
mysqlnd.collect_memory_statistics = On
[OCI8]
[PostgreSQL]
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
[bcmath]
bcmath.scale = 0
[browscap]
[Session]
session.save_handler = files
session.use_strict_mode = 0
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.serialize_handler = php
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.sid_length = 26
session.trans_sid_tags = "a=href,area=href,frame=src,form="
session.sid_bits_per_character = 5
[Assertion]
zend.assertions = 1
[COM]
[mbstring]
[gd]
[exif]
[Tidy]
tidy.clean_output = Off
[soap]
soap.wsdl_cache_enabled=1
soap.wsdl_cache_dir="/tmp"
soap.wsdl_cache_ttl=86400
soap.wsdl_cache_limit = 5
[sysvshm]
[ldap]
ldap.max_links = -1
[dba]
[opcache]
[curl]
[openssl]

新增项目配置:

vim /data1/www/php/fpm.d/mydemo.com.conf

 [mydemo.com]
user = www
group = www
listen = 127.0.0.1:9023
listen.allowed_clients = 127.0.0.1
pm = dynamic
pm.max_children = 512
pm.start_servers = 5
pm.min_spare_servers = 4
pm.max_spare_servers = 64
pm.max_requests = 1500

;pm.status_path = /dpool_monitor


slowlog = logs/$pool-slow_log
request_slowlog_timeout = 2

request_terminate_timeout = 30
catch_workers_output = no
security.limit_extensions = ""

access.log=logs/php-fpm_$pool.access.log
access.format = "%R - %u %t "%m %r%Q%q" %s %f %{mili}d %{kilo}M %C%%"

启动命令:

/usr/local/php/sbin/php-fpm -c /data1/www/php/php.ini  -y /data1/www/php/php-fpm.conf  -p /data1/www

平滑重启:

kill -USR2  fpm-pid

docker 制作自己的 php-fpm镜像

php-fpm的镜像官方已经有了,但是直接拿过来用或许不行,不同的项目所需要的扩展不一定一样。所以这里我们以官方的php-fpm 5.6版本为基础镜像,在这个镜像上制作我们自己的镜像。开发环境安装尽可能多的扩展,线上环境则安装所需要的扩展。

为了构建我们的镜像,首先需要一个名为Dockerfile的文件,docker会根据这个Dockerfile来构建镜像。

首先使用FROM指令,表示当前构建的镜像的基础镜像

FROM php:5.6-fpm

docker会从他自己的镜像库中拉取php-fpm5.6的镜像。

然后我们使用RUN指令来在这个镜像中执行一些指令。实际上RUN后面接着的就是linux的命令。比如apt-get,mkdir等等。

我们需要的是在这个镜像中安装一些php的扩展。可以使用RUN phpize,然后RUN make等一系列的命令来编译安装。不过docker里面内置了一个脚本,名为docker-php-ext-install,这个脚本会在/usr/src/php/ext的目录寻找扩展,并且编译安装,比我们自己编译然后写入配置要方便一些,所以我们就使用docker-php-ext-install来安装扩展啦。

比如我们需要安装redis

# install redis
RUN curl -L -o /tmp/redis.tar.gz http://pecl.php.net/get/redis-3.1.4.tgz 
&& tar xvf /tmp/redis.tar.gz 
&& rm -r /tmp/redis.tar.gz 
&& mkdir -pv /usr/src/php/ext 
&& mv redis-3.1.4 /usr/src/php/ext/redis 
&& docker-php-ext-install redis

上面的步骤就是首先下载redis,解压,移动到/usr/src/php/ext/里面,最后使用docker-php-ext-install编译和安装扩展就可以。同样,安装任何php的扩展都可以使用这个步骤来安装。

最后就是使用docker build命令来构建镜像,命令如下

docker build -t [镜像名称] [Dockerfile所在文件夹]

至此,一个我们自己的php-fpm镜像就构建完成,使用docker images看看镜像是不是已经存在啦!

Docker容器资源限制测试

Docker运行时的容器本质是进程。在Linux中,通过Namespace进行资源隔离,Cgroups进行资源限制。

一、Docker容器Cpu资源限制测试

容器资源CPU限制设置测试

默认所有的容器对于 CPU 的利用占比都是一样的,-c 或者 –cpu-shares 可以设置 CPU 利用率权重,默认为 1024,可以设置权重为 2 或者更高(单个 CPU 为 1024,两个为 2048,以此类推)。如果设置选项为 0,则系统会忽略该选项并且使用默认值 1024。通过以上设置,只会在 CPU 密集(繁忙)型运行进程时体现出来。当一个 container 空闲时,其它容器都是可以占用 CPU 的。cpu-shares 值为一个相对值,实际 CPU 利用率则取决于系统上运行容器的数量。

假如一个 1core 的主机运行 3 个 container,其中一个 cpu-shares 设置为 1024,而其它 cpu-shares 被设置成 512。当 3 个容器中的进程尝试使用 100% CPU 的时候「尝试使用 100% CPU 很重要,此时才可以体现设置值」,则设置 1024 的容器会占用 50% 的 CPU 时间。如果又添加一个 cpu-shares 为 1024 的 container,那么两个设置为 1024 的容器 CPU 利用占比为 33%,而另外两个则为 16.5%。简单的算法就是,所有设置的值相加,每个容器的占比就是 CPU 的利用率,如果只有一个容器,那么此时它无论设置 512 或者 1024,CPU 利用率都将是 100%。当然,如果主机是 3core,运行 3 个容器,两个 cpu-shares 设置为 512,一个设置为 1024,则此时每个 container 都能占用其中一个 CPU 为 100%。

1.1、通过参数–cpu-shares分配cpu使用权重

现在运行两个测试 container,一个权重设置为 2,一个权重设置 4,启动命令如下:

[root@ok188 ~]# docker run -it -d --cpu-shares 2 --name 2_cpu centos:7 /bin/bash
f3f125f7455974be77e58c0864d045b3b56ae2d007bd9095c47faca50893547c
[root@ok188 ~]# docker run -it -d --cpu-shares 4 --name 4_cpu centos:7 /bin/bash
5e623b55a22ef6d1e41e5978dd1c5d05d743b3a91498697db3b4b9c493f03f8b

通过压测工具如Stress进行压测,Stress使用实例:

  • 产生13个cpu进程4个io进程1分钟后停止运行
[root@ok188 ~]# stress -c 13 -i 4 --verbose --timeout 1m
  • 测试硬盘,通过mkstemp()生成800K大小的文件写入硬盘,对CPU、内存的使用要求很低
[root@ok188 ~]# stress -d 1 --hdd-noclean --hdd-bytes 800k
  • 产生13个进程,每个进程都反复不停的计算由rand ()产生随机数的平方根
[root@ok188 ~]# stress -c 13
  • 向磁盘中写入固定大小的文件,这个文件通过调用mkstemp()产生并保存在当前目录下,默认是文件产生后就被执行unlink(清除)操作,但是可以使用–hdd-bytes选项将产生的文件全部保存在当前目录下,这会将你的磁盘空间逐步耗尽
# 生成小文件
[root@ok188 ~]# stress -d 1 --hdd-noclean --hdd-bytes 13
# 生成大文件
[root@ok188 ~]# stress -d 1 --hdd-noclean --hdd-bytes 3G

对两个容器同时进行 CPU压测,在宿主机中查看两个容器CPU占用情况

[root@ok188 ~]# docker stats 2_cpu
CONTAINER      CPU %         MEM USAGE / LIMIT     MEM %      NET I/O         BLOCK I/O                 
2_cpu          33.31%        24.34MiB / 1.932GiB   1.23%     18.2MB / 322kB   49.1MB / 27.7MB
[root@ok188 ~]# docker stats 4_cpu
CONTAINER     CPU %         MEM USAGE / LIMIT     MEM %      NET I/O          BLOCK I/O                
4_cpu         65.96%        38.82MiB / 1.932GiB   1.96%     18.3MB / 451kB    8.19kB / 27.7MB

观察以上结果发现容器名为4_cpu权重比2_cpu大2倍,所以4_cpu可使用的cpu更多。
停止压测名为4_cpu的容器, 在宿主机中查看两个容器CPU占用情况

[root@ok188 ~]# docker stats 2_cpu
CONTAINER      CPU %         MEM USAGE / LIMIT     MEM %      NET I/O         BLOCK I/O                 
2_cpu          99.50%        24.34MiB / 1.932GiB   1.23%     18.2MB / 322kB   49.1MB / 27.7MB
[root@ok188 ~]# docker stats 4_cpu
CONTAINER     CPU %         MEM USAGE / LIMIT     MEM %      NET I/O          BLOCK I/O                
4_cpu         0.00%         37.5MiB / 1.932GiB   1.90%     18.3MB / 452kB    8.19kB / 27.7MB

结论参数cpu-shares 只是设置cpu使用权重,只会在 CPU 密集(繁忙)型运行进程时体现出来。当一个 container 空闲时,其它容器都是可以占用 CPU 的。
备注:物理主机为多核的情况下,显示的cpu使用比例有差异,本人测试主机为单核。

1.2、通过 –cpu-period & –cpu-quota 限制容器的 CPU 使用上限

默认的 CPU CFS「Completely Fair Scheduler」period 是 100ms。我们可以通过 –cpu-period 值限制容器的 CPU 使用。一般 –cpu-period 配合 –cpu-quota 一起使用。

为啥把这两个参数放一起呢?因为这两个参数是相互配合的,–cpu-period和–cpu-quota的这种配置叫Ceiling Enforcement Tunable Parameters,–cpu-shares的这种配置叫Relative Shares Tunable Parameters。–cpu-period是用来指定容器对CPU的使用要在多长时间内做一次重新分配,而–cpu-quota是用来指定在这个周期内,最多可以有多少时间用来跑这个容器。跟–cpu-shares不同的是这种配置是指定一个绝对值,而且没有弹性在里面,容器对CPU资源的使用绝对不会超过配置的值。

设置 cpu-period 为 100000,cpu-quota 为 50000,表示最多可以使用 cpu到50%。

[root@nsj-13-58 ~]# docker run -it --cpu-period=100000 --cpu-quota=50000 --name 0.5_p_cpu centos:7 /bin/bash

压测容器,并查看CPU占用情况:

[root@ok188 ~]# docker stats 0.5_p_cpu
CONTAINER       CPU %     MEM USAGE / LIMIT     MEM %         NET I/O             BLOCK I/O
0.5_p_cpu       50.33%    22.12MiB / 1.932GiB   1.12%         18.3MB / 348kB      524kB / 27.7MB

通过以上测试可以得知,–cpu-period 结合 –cpu-quota 配置是固定的,无论宿主机系统 CPU 是闲还是繁忙,如上配置,容器最多只能使用 CPU 到 50%。

二、Docker容器Memory资源限制测试

默认启动一个container,对于容器的内存是没有任何限制的。

2.1、默认启动一个 container,对于容器的内存是没有任何限制的。

[root@ok188 ~]# docker run -it -d --name no_limit_memory centos:7 /bin/bash
[root@ok188 ~]# docker stats no_limit_memory
CONTAINER           CPU %      MEM USAGE / LIMIT   MEM %      NET I/O             BLOCK I/O
no_limit_memory     0.00%      932KiB / 1.932GiB   0.05%      586B / 0B           8.19kB / 0B         
[root@ok188 ~]# free -g
              total        used        free      shared  buff/cache   available
Mem:              1           0           0           0           1           1
Swap:             1           0           1

MEM LIMIT显示的是容器宿主机的内存大小,Mem+Swap的总大小

2.2、通过 -m 参数限制内存大小

设置-m值为500Mb,表示容器程序使用内存受限。按照官方文档的理解,如果指定 -m 内存限制时不添加 –memory-swap 选项,则表示容器中程序可以使用 500m内存和500m swap 内存。那么容器里程序可以跑到500m*2=1g后才会被oom给杀死。

[root@ok188 ~]# docker run -it -d -m 500m --name limit_memory_1 centos:7 /bin/bash     
21eb95cffa45972603cb0e67b7ee0724d019cd7182fa5668bf07665ddf4f83cc
[root@ok188 ~]# docker stats limit_memory_1
CONTAINER           CPU %       MEM USAGE / LIMIT   MEM %      NET I/O             BLOCK I/O
limit_memory_1      0.00%       916KiB / 500MiB       0.09%      586B / 0B           0B / 0B

在libcontainer源码里

memory.memsw.limit_in_bytes

值是被设置成我们指定的内存参数的两倍。

其中代码如下:

// By default, MemorySwap is set to twice the size of RAM.
// If you want to omit MemorySwap, set it to `-1'.
if d.c.MemorySwap != -1 {
if err := writeFile(dir, "memory.memsw.limit_in_bytes", strconv.FormatInt(d.c.Memory*2, 10)); err != nil {
return err
}

使用压测工具进行压测,当压测值是 memory + swap之和上限时,则容器中的进程会被直接 OOM kill。

2.3、参数–memory-swappiness=0 表示禁用容器 swap 功能。

[root@ok188 ~]# docker run -it -d -m 500m --memory-swappiness=0 --name limit_memory_noswap_1 centos:7 /bin/bash

使用压测工具进行压测,当压测值是 1G ,则容器中的进程会被直接 OOM kill。查看容器内系统日志:

2.4、指定限制内存大小并且设置 memory-swap 值为 -1

表示容器程序使用内存受限,而 swap 空间使用不受限制(宿主 swap 支持使用多少则容器即可使用多少。如果 –memory-swap 设置小于 –memory 则设置不生效,使用默认设置)。–memory-swap -1

[root@ok188 ~]# docker run -it -d -m 500m --memory-swap -1  --name limit_memory_2 centos:7 /bin/bash

2.5、指定限制内存大小并且设置 memory-swap 值

指定限制内存大小500Mb并且设置 memory-swap 值400Mb当压测值是900Mb时,则容器中的进程会被直接 OOM kill。

[root@ok188 ~]# docker run -it -d -m 500m --memory-swap 400m  --name limit_memory_3 centos:7 /bin/bash

备注:实际生产环境不推荐使用swap功能,建议直接禁用swap功能。

2.6、参数–oom-kill-disable ,加上之后则达到限制内存之后也不会被 kill

正常情况不添加 –oom-kill-disable 容器程序内存使用超过限制后则会直接 OOM kill,加上之后则达到限制内存之后也不会被 kill。

[root@ok188 ~]# docker run -it -d -m 500m --oom-kill-disable --name limit_memory_4 centos:7 /bin/bash

==注意如果是以下的这种没有对容器作任何资源限制的情况,添加 –oom-kill-disable 选项就比较危险了:==

[root@ok188 ~]# docker run -it -d --oom-kill-disable --name limit_memory_5 centos:7 /bin/bash

因为此时容器内存没有限制,使用的上限值是物理内存的上限值。 并且不会被 oom kill,此时系统则会 kill 系统进程用于释放内存。

后记:目前 Docker 支持的资源限制选项

未分类

附Docker容器限制源码路径:

github.com/opencontainers/runc/libcontainer/cgroups/fs

docker容器跨服务器的迁移方式export和save

程序放在docker里面迁移起来很是方便,像是以前的话,需要重新部署环境和静态文件。 放在docker里面的话,只是需要export备份封装后,scp、rsync迁移到别的服务器就可以了。

[root@zhdy01 ~]# docker ps -a

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

6712e7adee85        665e                "/bin/bash"         28 seconds ago      Up 24 seconds                           youthful_perlman

[root@zhdy01 ~]# docker export 6712 > centos7_nginx.tar

[root@zhdy01 ~]# du -sh centos7_nginx.tar 

359M centos7_nginx.tar

然后把这个centos7_nginx.tar 传到别的服务器上。

[root@zhdy01 ~]# cat centos7_nginx.tar |docker import - c7_nginx
sha256:da676fc85a74162743df4d18d7983017e011b288a95cc503edd4fe229f207d25
[root@zhdy01 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
c7_nginx latest da676fc85a74 8 seconds ago 364MB
centos7_nginx latest 665e56a46000 6 days ago 385MB

上面的方式是用docker export。 export是当前的状态,docker save 是针对镜像images。

主要的区别是 save是可以回滚以前的配置。 export 只是当前的。

咱们用save 看看备份效果。 是1.1G ,这里是包含那些记录的。刚才咱们用export测试的时候,会发现文件只有300M左右。

来看看效果:(漫长的等待。。。)

[root@zhdy01 ~]# docker save centos7_nginx >centos7_nn.tar
[root@zhdy01 ~]# du -sh *
273M centos7_net.tar
359M centos7_nginx.tar
1.1G centos7_nn.tar

我估计如果有分布式文件系统 ,比如mfs,nfs。可以更好的试试用docker的数据卷来做本地文件夹和容器内的关联。 这样的话,备份更加自定义了。 毕竟环境这东西不会变,变的只是data数据,然后文件目录又在分布式文件里面,可以更好做迁移。只要那边启动一个环境,目录一关联就可以了。

备份迁移的方式自己选,推荐用export,毕竟save太大了,对于历史也没啥用处 !

对于数据安全关注更深的话,可以用docker volumes这样的数据映射。