Docker下的web开发和Tomcat部署

本期实践的主要目标是开发一个简单的web应用,打包部署到Docker的tomcat容器中去; 第一期为了快速上手,获取docker是从国内的daocloud获取的,本期开始,为了更好的熟悉和了解Docker技术,我们的查找,pull和push都改为在Docker Hub上进行,即网站:hub.docker.com,建议各位去上面注册一个账号,这样就有自己的仓库可以保存镜像了。

在hub.docker.com上搜索tomcat,搜索结果的第一个就是官方镜像,如下图:

未分类

点击Detail按钮,进入详情页,可以发现有好多个tag,例如7.0.75这个,就是tomcat7.0.75版本:

未分类

这么多版本,究竟选哪个呢?我们还是先看看几个具体版本的差异吧,打开tomcat官网下的这个链接:tomcat.apache.org/whichversio…

可以看到具体的差异:

未分类

可以看到,tomcat7 支持servlet3.0,可以满足我们的要求了,所以就用它吧,执行如下命令行即可下载镜像:

docker pull tomcat:7.0.75

命令执行有可能执行失败,多重试几次才行,pull成功后用docker images命令可以看到镜像:

未分类

来快速体验一下镜像的效果,执行命令:

docker run -it --rm -p 8888:8080 tomcat:7.0.75

–rm参数表示container结束时,Docker会自动清理其所产生的数据。

可以看到tomcat启动的日志全部打印在终端了,

未分类

因为我们用-p 8888:8080将容器的8080端口映射到当前电脑的8888端口,所以打开当前电脑的浏览器,输入:localhost:8888,可以看到熟悉的大猫:

未分类

接下来我们开发一个最简单的spring mvc应用,然后部署到docker的tomcat容器中试试,这我用的是IntelliJ IDEA CE,创建maven工程:

未分类

GAV信息如下:

未分类

如下图所示,通过这里增加一个mvn命令:

未分类

增加mvn命令:

未分类

配置命令如下:

未分类

接下来我们给web工程添加spring mvc支持,首先是web.xml文件,替换成下面这样:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1" metadata-complete="true">

  <servlet>
    <servlet-name>spring</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>

完整的pom文件内容如下:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.bolingcavalry</groupId>
  <artifactId>helloworldwebapp</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>helloworldwebapp Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.3.4.RELEASE</version>
    </dependency>
  </dependencies>
  <build>
    <finalName>helloworldwebapp</finalName>
  </build>
</project>

在编译的时候遇到了一点小问题需要在此提一下,在工程上点击右键查看module属性,如下图:

未分类

此时看到的信息如下图所示:

未分类

注意在上图的绿色框框位置,如果你的工程中没有看到绿色框框中的内容,就用鼠标右键点击红色框框位置,在弹出的菜单中点击”Sources”,这样就把java目录加入到工程的编译目录中去了。

这时候去执行mvn命令依然无法编译java文件,在工程上点击右键,执行mvn的reimport命令,如下图,执行完毕后就可以用mvn命令编译java文件了:

未分类

现在开始添加测试代码,先增加一个view目录,里面放个jsp文件,文件结构和jsp文件的内容如下:

未分类

再增加一个java文件,文件路径如下:

未分类

该文件的源码:

package com.bolingcavalry.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class FirstController {

    @RequestMapping(value = "firstview", method = RequestMethod.GET)
    public String index() {
        return "firstview";
    }
}

最后在webapp/WEB-INF目录下增加spring-servlet.xml文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd 
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context.xsd 
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 配置扫描的包 -->
    <context:component-scan base-package="com.bolingcavalry.*" />

    <!-- 注册HandlerMapper、HandlerAdapter两个映射类 -->
    <mvc:annotation-driven />

    <!-- 访问静态资源 -->
    <mvc:default-servlet-handler />

    <!-- 视图解析器 -->
    <bean
        class-og="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/view/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

</beans>

好了,代码已经写完,可以打包了,执行我们刚才配置好的命令,如下图:

未分类

命令执行后,可以在target目录下看到war包:

未分类

现在我们把文件部署到tomcat上去,先建一个目录,例如我建了这个目录:/Users/bolingcavalry/temp/201703/10/share,然后把helloworldwebapp.war文件复制到这个目录下,再在控制台执行以下命令:

docker run --name helloworldwebapp -p 8888:8080 -d -v /Users/bolingcavalry/temp/201703/10/share:/usr/Downloads tomcat:7.0.75

这样就启动了一个容器,执行以下命令进入容器

docker exec -it helloworldwebapp /bin/bash

进入容器后再执行以下命令将war包复制到tomcat容器目录下:

cp /usr/Downloads/helloworldwebapp.war /usr/local/tomcat/webapps/

这时候再打开浏览器,输入http://localhost:8888/helloworldwebapp/firstview试试吧,如下图,符合预期:

未分类

此时,我们今天测试tomcat部署的目的已经达到了,接下来再试试提交镜像,在容器中输入exit 退出容器,再执行”docker stop helloworldwebapp”停止容器,然后执行以下命令把容器作为镜像保存在本地:

docker commit -a "bolingcavalry" -m "from tomcat 7.0.75,with a demo webapp"  helloworldwebapp bolingcavalry/helloworldwebapp:0.0.1

-a : 作者
-m :提交时的说明文字
0.0.1:tag

执行完毕后,输入docker images,可以看到新增的镜像:

未分类

接下来我们试着把本地镜像提交到hub.docker.com去(前提是已经在这个网站上注册过),输入命令docker login,接下来按照提示输入用户名和密码,执行一下命令提交镜像:

docker push bolingcavalry/helloworldwebapp:0.0.1

有点费时,需要等待:

未分类

等上传成功后,再去hub.docker.com上看看吧,自己的仓库下面已经可以看到刚刚提交的镜像了:

未分类

Docker端口映射与容器互联

除了通过网络访问外,Docker还提供了两个很方便的功能来满足服务访问的基本需求:

  • 一个是允许映射容器内应用的服务端口到本地宿主主机;
  • 另一个是互联机制实现多个容器间通过容器名来快速访问。

端口映射实现访问容器

从外部访问容器应用

在启动容器时,如果不指定对应的参数,在容器外是无法通过网络访问容器内的网络应用和服务的。

当容器中运行一些网络应用,要让外部访问这些应用时,可以通过-P或-p参数来指定端口映射。当使用-P(大写)标记时,Docker会随机映射一个49000~49900的端口到内部容器开放的网络端口。

-p(小写)可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有IP:HostPort:ContainerPort | IP::ContainerPort | HostPort:ContainerPort。

映射所有接口地址

使用HostPort:ContainerPort默认会绑定所有接口上的所有地址,多次使用-p标记可以绑定多个端口。

docker run -d -p 5000:5000 -p 3000:80 training/webapp python app.py

映射到指定地址的指定端口

可以使用IP:HostPort:ContainerPort格式指定映射使用一个特定地址。

docker run -d -p 127.0.0.1:5000:5000 training/webapp python app.py

映射到指定地址的任意端口

可以使用IP::ContainerPort格式绑定指定地址任意端口到容器端口,本地主机会自动分配一个端口。

docker run -d -p 127.0.0.1::5000 training/webapp python app.py

查看映射端口配置

使用docker port命令可以查看当前映射的端口配置,也可以查看到绑定的地址:

docker port nostalgic_morse 5000

注意: 容器有自己的内部网络和IP地址,使用docker inspect + 容器ID可以获取容器的具体信息。

互联网机制实现便捷互访

容器的互联是一种让多个容器中应用进行快速交互的方式。它会在源和接收容器之间创建连接关系,接收容器可以通过容器名快速访问到源容器,而不用指定具体的IP地址。

自定义容器命名

连接系统依据容器的名称来执行,因此首先需要定义一个好记的容器名,虽然创建容器时系统会默认分配一个名字。

使用–name标记可以为容器自定义命名:

docker run -d -P --name web training/webapp python app.py

注意: 容器的名称是唯一的。如果已经命名了一个叫web的容器,当要再次使用web这个名称的时候,需要先用docker rm来删除之前创建的同名容器。

容器互联

使用–link参数可以让容器之间安全地进行交互。

–link参数的格式为–link name:alias,其中name是要连接的容器名称,alias是这个连接的别名。

新建一个web容器,并将它连接到db容器:

docker run -d -P --name web --link db:db training/webapp python app.py

使用docker ps可以看到db容器的names列有db,也有web/db,这表示web容器连接到db容器,这允许web容器访问db容器的信息。

Docker相当于在两个互联的容器之间创建了一个虚机通道,而且不用映射它们的端口到宿主机上。

docker通过两种方式来为容器公开连接信息

  • 更新环境变量
  • 更新/etc/hosts文件

使用env命令来查看web容器的环境变量:

$ docker run -rm --name web --link db:db training/webapp env
...
DB_NAME=/web2/db
DB_PORT=tcp://172.17.0.5:5432
DB_PORT_5000_TCP=tcp://172.17.0.5:5432
DB_PORT_5000_TCP_PROTO=tcp
...

其中DB_开头的环境变量是供web容器连接db容器使用的,前缀采用大写的连接别名。

除了环境变量之外,Docker还添加host信息到父容器的/etc/hosts文件。

下面是父容器web的hosts文件:

$ docker run -rm --name web --link db:db training/webapp /bin/bash
$ cat /etc/hosts
172.17.0.7 aed84ee21bde
...
172.17.0.5 db

这里有两个hosts信息,第一个是web容器,web容器用自己的id作为默认主机名,第二个是db容器的IP和主机名。

用户可以连接多个子容器到父容器。

CentOS 7 加速 docker源

对于使用 systemd 的系统,请在 /etc/docker/daemon.json 中写入如下内容(如果文件不存在请新建该文件)

{
  "registry-mirrors": [
    "https://registry.docker-cn.com"
  ]
}

注意,一定要保证该文件符合 json 规范,否则 Docker 将不能启动。

之后重新启动服务。

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

注意:如果您之前查看旧教程,修改了 docker.service 文件内容,请去掉您添加的内容(–registry-mirror=https://registry.docker-cn.com),这里不再赘述。

如何做好Docker资源管控?

Docker资源管控配额原理

Docker同LXC一样,其对资源的隔离和管控是以Linux内核的namespaces和cgroups为基础。Docker的资源隔离使用了Linux内核 Kernel中的Namespaces功能来实现,隔离的对象包括:主机名与域名、进程编号、网络设备、文件系统的挂载点等,namespace中的IPC隔离docker并未使用,docker中使用TCP替代IPC。

在使用Namespaces隔离资源的同时,Docker使用了Linux内核Kernel提供的cgroups来对Container使用的CPU、内存、磁盘IO资源进行配额管控。换句话说,在docker的容器启动参数中,像—cpu、–memory和—blkio*的设置,实际上就是设置cgroups的相对应cpu子系统、内存子系统、磁盘IO子系统的配额控制文件,只不过这个修改配额控制文件的过程是docker实例代替我们做掉罢了。

因此,我们完全可以直接修改docker容器所对应的cgroup子系统中的配额控制文件来达到控制docker容器资源配额的同样目的,接下来将以IO控制为例,介绍一下具体实现过程。

物理部署架构图

实验测试环境物理部署图如下:

未分类

整体的部署思路如下:

1、 将物理磁盘进行分区操作(此步骤可选)
2、将分区创建为物理卷(PV)并添加到卷组(VG)中
3、从卷组(VG)中创建出逻辑卷(LV),并将该卷格式化后挂载供docker使用
4、将步骤3中逻辑卷挂载点再挂载到docker镜像容器中

管控配额过程

1、将磁盘设备/dev/sdb进行分区,分别为sdb1和sdb2

未分类

2、创建PV

pvcreate /dev/sdb2  #使用sdb2创建物理卷(PV)

未分类

3、创建VG

vgcreate datavg /dev/sdb2 #vg名称为datavg

未分类

4、创建LV,并格式化

lvcreate  -n  datalv  datavg  && mkfs.ext4 /dev/mapper/datavg-datalv

未分类

5、创建目录并挂载

mkdir /data && mount /dev/mapper/datavg-datalv /data

未分类

测试验证

1、使用docker镜像docker.io/learn/tutorial :jiangzt作为测试容器

未分类

2、不加配额参数的情况下启动容器

启动容器时不配额参数,并观察其所在的cgroups子系统的配置情况。

docker run -dit -h inner --name test -v /data:/data a36927dbb31f /bin/bash

未分类

根据容器ID观察cgroups下blkio子系统的配置情况,结果是文件blkio.throttle.write_bps_device中没有内容。

未分类

进入容器内,执行dd命令,测试观察此时默认的写入IO能力。

docker exec -it test  /bin/bash
time dd if=/dev/zero of=/data/test.out bs=1M count=1024 oflag=direct

未分类

可以得知写入的平均速度是 2.1GB/s

3、使用参数device-write-bps启动容器

启动容器增加配额参数device-write-bps,写入目标速度为1mb/s,并观察其所在的cgroups子系统的配置情况。

docker run -dit  -m 100m -h inner --name test --device-write-bps /dev/dm-6:1mb  -v /data:/data a36927dbb31f /bin/bash

说明:lv的设备名称/dev/dm-6可以通过dmsetup做查询

未分类

容器启动后根据容器id观察cgroups子系统中的配置情况。

未分类
未分类

在cgroups的blkio.throttle.write_bps_device文件中观察到了253:6 1048576 就是我们在启动docker时指定的–device-write-bps参数值,设备为253:6(/dev/dm-6),io能力为1048576byte(1mb)

进入容器内,执行dd命令,测试观察此时默认的写入IO能力

未分类

可以观察到此时的写入速度为1.0MB/s

4、直接修改cgroup中的参数配置

前面在原理介绍时提过,docker其实也是修改cgroup中的参数来控制资源的使用,那么我们直接修改blkio.throttle.write_bps_device,然后观察是否能直接作用于docker容器,还是使用上面的容器id进行操作,将blkio.throttle.write_bps_device中的内容修改为10MB/s。
echo 253:6 10485760 > blkio.throttle.write_bps_device
进入容器内,执行dd命令,测试观察此时默认的写入IO能力。

未分类

可以看到通过直接修改cgroup中的blkio.throttle.write_bps_device的速度值起到了作用。

5、对于其他参数的控制分析

细心的你可能已经发现在docker镜像时,还有个参数-m 100m,该参数是用来控制容器使用内存的配额,我们可以通过docker stats进行验证。

未分类

同样我们也是可以在cgroup的内存子系统中看到相应的参数配置。

总结

通过以上的分析测试,进一步熟悉了解了docker运行时的行为和所依赖的底层的技术原理,希望能够为docker的自动化运维开发提供解决思路和办法。

Docker-MySql — 使用mysqldump 命令备份导出mysql容器中的结构数据

1. 查看当前启动的mysql运行容器

docker ps   

2. 使用以下命令备份导出数据库中的所有表结构和数据

docker exec -it  mysql mysqldump -uroot -p123456 paas_portal > /cloud/sql/paas_portal.sql  

3.只导数据不导结构

mysqldump -t 数据库名 -uroot -p > xxx.sql 
docker exec -it mysql mysqldump -t -uroot -p123456 paas_portal >/cloud/sql/paas_portal_dml.sql  

4. 只导结构不导数据

mysqldump --opt -d 数据库名 -u root -p > xxx.sql 
docker exec -it mysql mysqldump  --opt -d   -uroot -p123456 paas_portal >/cloud/sql/paas_portal_ddl.sql   

5. 导出特定表的结构

mysqldump -uroot -p -B 数据库名 --table 表名 > xxx.sql
docker exec -it mysql mysqldump -uroot -p -B paas_portal --table user > user.sql  

这是工作中用到的,记录下来,以供学习参考

Docker compose初始化失败问题

问题

今天在Docker Postgresql用户名和密码授权的问题上花了一些时间,问题是:

psql: FATAL:  password authentication failed for user "postgres"

admin的用户名和密码是可以在docker-compose.yml里设置的,通常我们可以配置为:

postgresql:
  image: postgres:latest
  ports:
    - "5434:5432"
  volumes:
    - ./data/pgsql:/var/lib/postgresql/data
    - ./initialize/pgsql:/docker-entrypoint-initdb.d
  environment:
    POSTGRES_USER: postgres
    POSTGRES_DB: postgres
  secrets:
    - pg_superuser_password

某个用户的密码可以在./initialize/pgsql目录的脚本里设置:

#!/bin/bash
set -e
psql -v ON_ERROR_STOP=1 --username "postgres" <<-EOSQL
    CREATE USER user WITH PASSWORD 'the-password';
    ALTER USER user CREATEDB;
EOSQL

只是今天碰巧想修改一下这个密码,所以就把这个脚本里的密码修改了,然后执行命令:

docker-compose up --build -d --force-recreate

而后就一直出现上面的用户授权失败。

原因

刚开始一直认为是可能dockerfile配置得不对,结果花费了些时间。后来突然想到了,PG里数据初始化应该只是第一次做了,后续如果发现/var/lib/postgresql/data里已经有数据了就再也不会重新设置密码,这里是配置volume的,如果还未有重要数据把./data/pgsql删除了即可,或者应该是可以通过attach进入容器通过pg命令修改。

总结

最近在自己工作的项目都完全Docker化,感觉是配置来折腾用起来飞。最近也在做一个重度依赖Docker的项目,所以Docker的文档需要看完,特别是网络和数据存储那块,否则会花费不少时间折腾。

Docker Compose 常用命令

docker-compose 命令

大多数Compose命令都是运行于一个或多个服务的,如果服务没有指定,该命令将会应用到所有服务,如果要获得所有可用信息,使用命令:docker-compose [COMMAND] –help

build
创建或者再建服务
服务被创建后会标记为project_service(比如composetest_db),如果改变了一个服务的Dockerfile或者构建目录的内容,可以使用docker-compose build来重建它

help
显示命令的帮助和使用信息

kill
通过发送SIGKILL的信号强制停止运行的容器,这个信号可以选择性的通过,比如:
docker-compose kill -s SIGKINT

logs
显示服务的日志输出

logs 后面什么都不加,则输出该项目所有服务的日志信息

docker-compose logs SERVICE 则输出该服务的日志信息

port

为端口绑定输出公共信息

ps
显示容器

pull
拉取服务镜像

rm
删除停止的容器

run
在服务上运行一个一次性命令,比如:
docker-compose run web python manage.py shell

scale
设置为一个服务启动的容器数量,数量是以这样的参数形式指定的:service=num,比如:
docker-compose scale web=2 worker=3

start
启动已经存在的容器作为一个服务

stop
停止运行的容器而不删除它们,它们可以使用命令docker-compose start重新启动起来

up
为一个服务构建、创建、启动、附加到容器
连接的服务会被启动,除非它们已经在运行了
默认情况下,docker-compose up会集中每个容器的输出,当存在时,所有的容器会停止,运行docker-compose up -d会在后台启动容器并使它们运行

top

显示容器中运行的进程

选项

–verbose
显示更多输出

–version
显示版本号并退出

-f,–file FILE
指定一个可选的Compose yaml文件(默认:docker-compose.yml)

-p,–project-name NAME
指定可选的项目名称(默认:当前目录名称)

使用 Docker Compose 本地部署基于 Sentinel 的高可用 Redis 集群

说明

项目地址:github.com/TomCzHen/re…

根据官方文档 Redis Sentinel Documentation 中的 Example 2: basic setup with three boxes 示例创建的实例,但因为是单机部署,所以不满足 Redis 实例 与 Sentinel 实例分别处于 3 台机器的要求,因此仅用于开发环境测试与学习。

使用方法

  • 使用 docker-compose up -d 部署运行。

  • 使用 docker-compose pause master 可以模拟对应的 Redis 实例不可用。

  • 使用 docker-compose pause sentinel-1 可以模拟对应的 Sentinel 实例不可用。

  • 使用 docker-compose unpause service_name 将暂停的容器恢复运行。

  • 使用支持 Sentinel 的客户端连接 localhost:62379 进行应用测试。

注:Windows 和 Mac 可能需要修改 Volumes 挂载参数。

注意事项

Sentinel, Docker, NAT, and possible issues

https://redis.io/topics/sentinel#sentinel-docker-nat-and-possible-issues

将容器端口 EXPOSE 时,Sentinel 所发现的 master/slave 连接信息(IP 和 端口)对客户端来说不一定可用。

例如:将 Reids 实例端口 6379 EXPOSE 为 16379, Sentinel 容器使用 LINK 的方式访问 Redis 容器,那么对于 Sentinel 容器 6379 端口是可用的,但对于外部客户端是不可用的。

解决方法是 EXPOSE 端口时保持内外端口一致,或者使用 host 网络运行容器。如果你想使用本项目中的编排文件部署的集群对外部可用,那么只能将 Redis 容器运行在 host 网络之上。

注:实际上 bridge 模式下 Redis 性能也会受到影响。

文件结构

.
├── docker-compose.yaml
├── nginx
│   └── nginx.conf
├── README.md
├── .env
└── sentinel
    ├── docker-entrypoint.sh
    ├── Dockerfile-sentinel
    └── sentinel.conf.sample

Sentinel

镜像使用 Dockerfile-sentinel 构建,运行时根据环境变量生成 sentinel.conf 文件,详细配置说明请查看 sentinel.conf.sample 内容。

docker-entrypoint.sh

使用 Reids 官方镜像中的 docker-entrypoint.sh 脚本修改而来,添加了生成 sentienl.conf 语句。

...
# create sentinel.conf
if [ ! -e ${SENTINEL_CONF_PATH} ]; then
    envsubst < /etc/redis/sentinel.conf.sample > ${SENTINEL_CONF_PATH}
    chown redis:redis /etc/redis/sentinel.conf
fi
...

修改配置 Sentinel 的环境变量后需要重新创建容器才能生效。

可用环境变量

SENTINEL_CONF_PATH=/etc/redis/sentinel.conf
SENTINEL_PORT=26379
SENTINEL_MASTER_NAME=redis-master
SENTINEL_REDIS_IP=127.0.0.1
SENTINEL_REDIS_PORT=6379
SENTINEL_REDIS_PWD=
SENTINEL_QUORUM=2
SENTINEL_DOWN_AFTER=30000
SENTINEL_PARALLEL_SYNCS=1
SENTINEL_FAILOVER_TIMEOUT=180000

docker-compose.yaml

可以使用 docker-compose config 可查看完整的编排内容。

Redis 实例运行参数

详细可用参数请查看官方示例文件 Redis Configuration File Example,需要注意 port 参数需要与编排中的 PORTS 保持一致,或修改编排文件让容器网络使用 host 模式。

由于 master 会被 Sentinel 切换为 slave ,因此最好保持每个 Redis 实例的口令一致。

master:
    image: redis:4.0.8-alpine
    ports:
      - 6379:6379
    volumes:
      - type: volume
        source: master-data
        target: /data
    command: [
      '--requirepass "${REDIS_PWD}"',
      '--masterauth "${REDIS_PWD}"',
      '--maxmemory 512mb',
      '--maxmemory-policy volatile-ttl',
      '--save ""',
    ]

Sentinel 实例运行参数

详细可用参数请查看 sentinel 目录下的 sentinel.conf.sample 文件。由于容器使用的配置文件是运行时根据环境变量生成的,因此使用 environment 进行配置,可用环境变量请查看文档 Sentinel 部分。

最后使用了 Nginx 作为 Sentinel 实例的代理,因此 Sentinel 容器不需要对外访问。

sentinel-1: &sentinel
    build:
      context: ./sentinel
      dockerfile: Dockerfile-sentinel
    image: redis-sentinel:dev
    environment:
      - SENTINEL_REDIS_PWD=${REDIS_PWD}
      - SENTINEL_REDIS_IP=${SENTINEL_MASTER_NAME}
      - SENTINEL_QUORUM=2
      - SENTINEL_DOWN_AFTER=3000
    command: [
      '${SENTINEL_CONF_PATH}',
      '--sentinel'
    ]
    depends_on:
      - master
      - node-1
      - node-2
    links:
      - master:${SENTINEL_MASTER_NAME}
      - node-1
      - node-2
  sentinel-2:
    <<: *sentinel
  sentinel-3:
    <<: *sentinel

Nginx

使用 Nginx 作为 Sentinel 负载均衡以及高可用代理。

  nginx:
    image: nginx:1.13.9-alpine
    ports:
      - 26379:26379
    volumes:
      - type: bind
        source: ./nginx/nginx.conf
        target: /etc/nginx/nginx.conf
        read_only: true
    depends_on:
      - sentinel-1
      - sentinel-2
      - sentinel-3

修改 nginx 目录下的 nginx.conf 进行配置。

...
stream {
    server {
        listen 26379;
        proxy_pass redis_sentinel;
    }

    upstream redis_sentinel {
        server sentinel-1:26379;
        server sentinel-2:26379;
        server sentinel-3:26379;
    }
}
...

你离ELK只有一句docker-compose的距离

未分类

引言

刚接触Elk的时候,我用github.com/deviantony/…,部署了第一个测试环境,这是一个很优秀的项目,几乎没什么配置就可以部署成功。
但有一个问题就是对于一个初学者如此洁净的环境,我完全不知道从何入手,也弄不清这个框架的优势是什么(连个Dashboard样本都没有)。还有 x-pack 的配置,metricbeat 的接入都踩过不少坑,才部署成一个像样的学习环境。之后在写 docker-compose.yml 脚本的时候又是各种踩雷,终于实现了快速一键部署。同时支持 DaoCloud 的 Stack 脚本 持续集成
在这里分享给大家,好像想入坑的同学少走些弯路。

你需要准备什么

一个 docker 环境, 还有…… 没了

注:win 和 macOS 下不支持 docker-metricbeat 的 system 监控,需手动关闭

我要怎么做

在这里看下注意事项

本地部署

$ git clone "https://github.com/wilfordw/docker-elk-example.git"
$ cd docker-elk-example
$ docker-compose up -d

DaoCloud Stack 部署

先下载项目到服务器,复制项目绝对路径

$ git clone "https://github.com/wilfordw/docker-elk-example.git"
$ cd docker-elk-example
$ pwd

把 dao-docker-compose.yml 内容复制进 Stack 的 YAML, 把上面克隆项目的 pwd 替换里面的 /root/app/docker-elk/, 点击部署就可以

想要自己创建镜像也可以,把你创建好的镜像地址替换 yml 里的 image

部署完可以看到什么?

未分类

未分类

未分类

未分类

未分类

未分类

继续更新

目前只做了 System Docker Nginx 的监控案列, 之后会继续集成

  • Metricbeat Mysql 监听
  • Metricbeat NodeJs 监听
  • Metricbeat Golang 监听
  • Metricbeat Kubernetes 监听
  • X-pack 权限解析
  • ELK 集群