使用bash脚本自定义创建postgres docker容器

1. 查看镜像库中postgres镜像

Docker search postgres 

2. 下载镜像

docker pull postgres

3.查看镜像

docker images

4.配置sh脚本

mkdir  postgres  (创建文件夹)

cd postgres 

mkdir data (创建数据文件夹)

touch postgres.sh (常见sh脚本文件)

vi postgres.sh(编辑脚本)

粘贴以下代码到postgres.sh文件中

#!/bin/sh  

NAME=hy-postgres  
PORT=5432  
CURDIR=`pwd`  
PASSWORD=123456  
case "$1" in  
    create)  
        port_map="-p 172.17.0.1:5432:5432"  
        volumn_map="-v $PWD/data:/data"  
        env_map="-e POSTGRES_PASSWORD=$PASSWORD"   
        docker run --name $NAME -d $env_map $port_map $volumn_map postgres:9.4.3  
        ;;  
    delete)  
        docker rm $NAME  
        ;;  
    start)  
        docker start $NAME  
        ;;        
    stop)  
        docker stop $NAME  
        ;;  
    status)  
        docker ps -a | grep $NAME  
        ;;  
    restart)  
        docker restart $NAME  
        ;;    
    bash)  
        docker exec -it $NAME bash  
        ;;  
    exec)  
        shift  
        docker exec -it $NAME $*  
        ;;  
    *)  
        echo "Usage: $0 {start|stop|status|bash|exec|restart}"  
        exit 1  
    ;;  
esac  

5. 使用脚本启动镜像

./postgres.sh create(创建镜像)

./postgres.sh start(启动镜像)

利用docker-compose安装lnmp(Nginx mariadb php7.0 )

对于Docker来说,最大的便利就是能快速的搭建起一个个的容器,容器之间可以通过网络和文件来进行通信。

之前我已经将自己的博客使用docker搭建起来了,这里简单记录一下docker-compose文件内容。

我的博客的架构为lnmp,依赖的容器有:

  • Nginx(Port:80)

  • mariadb(Port:3306)

  • wordpress+php7.0-fpm(Port:9000)

  • phpmyadmin(Port:8009)

docker-compose.yml文件内容如下

nginx:
    image: nginx:latest
    ports:
        - '80:80'
    volumes:
        - ./nginx:/etc/nginx/conf.d
        - ./logs/nginx:/var/log/nginx
        - ./jialeens:/var/www/html
    links:
        - wordpress
    restart: always

mysql:
    image: mariadb
    ports:
        - '3306:3306'
    volumes:
        - ./db-data:/var/lib/mysql
    environment:
        - MYSQL_ROOT_PASSWORD=******
    restart: always

wordpress:
    image: wordpress:4.8.0-php7.0-fpm
    ports:
        - '9000:9000'
    volumes:
        - ./jialeens:/var/www/html
    environment:
        - WORDPRESS_DB_NAME=***
        - WORDPRESS_TABLE_PREFIX=wp_
        - WORDPRESS_DB_HOST=mysql
        - WORDPRESS_DB_PASSWORD=*****
    links:
        - mysql
    restart: always
phpmyadmin:
  image: phpmyadmin/phpmyadmin
  links:
    - mysql
  environment:
    PMA_HOST: mysql
    PMA_PORT: 3306
  ports:
    - '8009:80'

Nginx配置文件:

jialeens.com.conf

server {
    listen 80;
    server_name jialeens.com www.jialeens.com;

    fastcgi_buffer_size 64k;
    fastcgi_buffers 4 64k;
    fastcgi_busy_buffers_size 128k;
    fastcgi_temp_file_write_size 128k;
    client_max_body_size 100m;
    root /var/www/html;
    index index.php;

    access_log /var/log/nginx/jialeens-access-http.log;
    error_log /var/log/nginx/jialeens-error-http.log;

    if ($host = 'jialeens.com') {
        return 301 http://www.jialeens.com$request_uri;
    }
    location ~* ^.+.(js|ico|gif|jpg|jpeg|png|html|htm)$ {
       log_not_found off;
       access_log off;
       expires 7d;
    }
    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ .php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+.php)(/.+)$;
        fastcgi_pass wordpress:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PHP_VALUE "upload_max_filesize=128M n post_max_size=128M";
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

因为流量不大,所以没做fastcgi的缓存,以后有空再弄吧。

Docker OOM事件介绍

OOM(Out Of Memory)内存不足,通常是由于某些不稳定的进程占用过多的内存造成,在Docker中称为OOM事件,当容器使用的内存过多时就会发生OOM事件,这个事件是由Linux内核的内存管理机制发起,并将是使用占用内存过多的容器Kill掉,保证系统的可持续运行。Linux内核为了保证系统的稳定性而将内存划分为两大部分用户空间与内核空间

未分类

用户空间是提供给用户进程所使用的内存空间。内核空间是仅提供给内核运行的空间。用户的进程是无法访问内核空间,而内核是可以访问用户空间与内核空间。在Linux内存管理机制中还存在一个定时任务,检查计算机的内存是否足够使用,分别收集以下几个指标

  • Total page cache as page cache is easily reclaimed
  • Total free pages because they are already available
  • Total free swap pages as userspace pages may be paged out
  • Total pages managed by swapper_space although this double-counts the free swap – pages. This is balanced by the fact that slots are sometimes reserved but not used
  • Total pages used by the dentry cache as they are easily reclaimed
  • Total pages used by the inode cache as they are easily reclaimed

如果内核发现内存不足够使用时开始发起OOM的状态检查,接着调用out-of-memory函数查找使用内存最多的进程并kill掉 oom

未分类

在Docker的容器中默认是没有限制资源使用的,也就是说容器获得到CPU/内存与宿主机是一样的,为了避免OOM事件,可以给Docker的容器作一些调整

  • 通过性能测试后才放到生产环境的容器中

  • 确保主机上有足够的资源分配

  • 使用SWAP(交换空间)

  • 将容器转换到有足够内存的Docker Swarm的服务中

注意:Docker不建议手动调整–oom-score-adj与–oom-disable-kill选项来避免OOM。

升级docker的方法

1、下载docker最近稳定版

curl -sSL -O https://get.docker.com/builds/Linux/x86_64/docker-1.9.1

2、停止docker服务并备份文件

service docker stop
mv /usr/bin/docker /usr/bin/docker_bak

3、升级docker

mv docker-1.9.1 /usr/bin/docker
chmod +x /usr/bin/docker
service docker start

4、查看最新版本

docker -v

Docker默认网络、自定义网络和overlay网络介绍

前言

前面总结了Docker基础以及Docker存储相关知识,今天来总结一下Docker单主机网络的相关知识。毋庸置疑,网络绝对是任何系统的核心,他在Docker中也占有重要的作用。同样本文基于CloudMan的系列教程。感谢ColudMan无私分享。

一、Docker默认网络

在新安装docker的主机上执行

docker network ls

便能看到docker默认安装的所有网络,分别是none网络、host网络和bridge网络。

1.1 none 网络

none网络就是什么都没有的网络。挂在这个网络下的容器除了lo,没有其他任何网卡。容器run时,可以通过添加–network=none参数来指定该容器使用none网络。那么这样一个只有lo的网络有什么用呢?此处CloudMan指出:

  • none网络应用与隔离场景,一些对安全性要求高并且不需要联网的应用可以使用none网络。

  • 比如某个容器的唯一用途是生成随机密码,就可以放到none网络中避免密码被窃取。

我可以理解none网络肯定是用于隔离的,然而我好奇的是生成的随机密码如何发送到外部呢?如何被外部调用呢?这是我没有想明白的问题。有知道的希望不吝赐教!谢谢!

1.2 host 网络

连接到host网络的容器共享Docker宿主机的网络栈,即容器的网络配置与host宿主机完全一样。可以通过添加–network=host参数来指定该容器使用host网络。

在容器中可以看到host的所有网卡,并且连hostname也是host的。host网络的使用场景又是什么呢?

直接使用Docker host的网络最大的好处就是性能,如果容器对网络传输效率有较高要求,则可以选择host网络。当然不便之处就是牺牲一些灵活性,比如要考虑端口冲突问题,Docker host上已经使用的端口就不能再用了。

Docker host的另一个用途是让容器可以直接配置 host 网路。比如某些跨host的网络解决方案,其本身也是以容器方式运行的,这些方案需要对网络进行配置。

相当于该容器拥有了host主机的网络,那么其ip等配置也相同,相当于主机中套了一个与外部一模一样的容器,可以直接通过host的ip地址来访问该容器。

1.3 bridge 网络

在不指定–network参数或者–network=bridge的情况下创建的容器其网络类型都是bridge。

Docker在安装时会在宿主机上创建名为docker0的网桥,所谓网桥相当于一个虚拟交换机,如果使用上述两种方式run的容器都会挂到docker0上。

容器和docker0之间通过veth进行连接,veth相当于一根虚拟网线,连接容器和虚拟交换机,这样就使得docker0与容器连通了。

二、自定义容器网络

理论上有了上述三种网络已经足够满足普通用户的需求,但是有时候可能用户需要指定自己的网络,以此来适应某些配置,如ip地址规划等等。

2.1 创建自定义网络

Docker提供三种user-defined网络驱动:bridge,overlay和macvlan。overlay和macvlan用于创建跨主机的网络,会在下一篇文章介绍。所以本文介绍创建bridge自定义网络。命令如下:

docker network create -d bridge --subnet 172.10.0.0/24 --gateway 172.10.0.1 my_net

-d bridge表示自定义网络的驱动为bridge,–subnet 172.10.0.0/24 –gateway 172.10.0.1分别指定网段和网关。

这样就创建好了一个自动一网络,可以通过以下命令查看此网络的信息:

docker network inspect my_net

会得到此网络的配置信息,my_net是刚刚创建的网络名称,如果为bridge就是查看docker创建的默认bridge网络信息。

每创建一个自定义网络便会在宿主机中创建一个网桥(docker0是创建的默认网桥,其实原理是一致的,而且也是对等的。)。名字为br-<网络短ID>,可以通过brctl show命令查看全部网桥信息。

docker的自定义网络与OpenStack中的网络信息倒是基本一致。所以一通百通,只要docker的明白了,所有虚拟化甚至实体的网络也就基本都搞清楚了。

2.2 使用自定义网络

通过以下命令为容器指定自定义网络:

docker run -it --network my_net --ip 172.10.0.3 busybox

其实这与使用docker默认网络是一致的,都是添加–network参数参数,此处也添加了–ip参数来指定容器的ip地址。

三、不同容器之间的连通性

同一个网络(默认网络或者自定义网络)下的容器之间是能ping通的,但是不同网络之间的容器由于网络独立性的要求是无法ping通的。原因是iptables-save DROP掉了docker之间的网络,大概如下:

-A DOCKER-ISOLATION -i docker0 -o br-ac4fe2d72b18 -j DROP
-A DOCKER-ISOLATION -i br-ac4fe2d72b18 -o docker0 -j DROP
-A DOCKER-ISOLATION -i br-62f17c363f02 -o br-ac4fe2d72b18 -j DROP
-A DOCKER-ISOLATION -i br-ac4fe2d72b18 -o br-62f17c363f02 -j DROP
-A DOCKER-ISOLATION -i br-62f17c363f02 -o docker0 -j DROP
-A DOCKER-ISOLATION -i docker0 -o br-62f17c363f02 -j DROP

那么如何让不同网络之间的docker通信呢?接下来介绍容器间通信的三种方式。

3.1 IP 通信

IP通信就是直接用IP地址来进行通信,根据上面的分析需要保证两个容器处于同一个网络,那么如果不在同一个网络如何处理呢?

如果是实体机我们很容易理解,只需要为其中一台服务器添加一块网卡连接到另一个网络就可以了。容器同理,只需要为其中一个容器添加另外一个容器的网络就可以了。使用如下命令:

docker network connect my_net httpd

connect命令能够为httpd容器再添加一个my_net网络(假设httpd原来只有默认的bridge网络)。这样上面创建的busybox容器就能与此次connect的httpd容器进行通信。

3.2 Docker DNS Server

通过 IP 访问容器虽然满足了通信的需求,但还是不够灵活。因为我们在部署应用之前可能无法确定IP,部署之后再指定要访问的IP会比较麻烦。对于这个问题,可以通过docker自带的DNS服务解决。

从Docker 1.10 版本开始,docker daemon 实现了一个内嵌的DNS server,使容器可以直接通过“容器名”通信。

方法很简单,只要在启动时用–name为容器命名就可以了。

下面的命令启动两个容器bbox1和bbox2:

docker run -it --network=my_net --name=bbox1 busybox
docker run -it --network=my_net --name=bbox2 busybox

然后,bbox2就可以直接ping到bbox1了,但是使用docker DNS有个限制,只能在user-defined网络中使用。默认的bridge网络是无法使用的。

3.3 joined 容器

joined 容器是另一种实现容器间通信的方式。joined 容器非常特别,它可以使两个或多个容器共享一个网络栈,共享网卡和配置信息,joined容器之间可以通过127.0.0.1直接通信。host网络使得容器与宿主机共用同一个网络,而jointed是使得两个容器共用同一个网络。

请看下面的例子:

先创建一个httpd容器,名字为web1。

docker run -d -it --name=web1 httpd

然后创建busybox容器并通过–network=container:web1指定jointed容器为web1:

docker run -it --network=container:web1 busybox

这样busybox和web1的网卡mac地址与IP完全一样,它们共享了相同的网络栈。busybox 可以直接用127.0.0.1访问web1的http服务。

其实也很容易理解,之前的–network参数指定了默认网络或者自定义网络,而此处是指定了一个容器,那么当然意思就是使用这个容器的网络。这也有点类似上一篇文章讲到的共享存储。

joined 容器非常适合以下场景:

  • 不同容器中的程序希望通过loopback高效快速地通信,比如web server与app server。

  • 希望监控其他容器的网络流量,比如运行在独立容器中的网络监控程序。

其实就是应用于即需要独立而又需要两个容器网络高度一致的场景。

3.4 容器与外部网络的连通性

  • 容器访问外部网络

容器默认是能访问外部网络的。通过NAT,docker实现了容器对外网(此处外网不一定是互联网)的访问。

  • 外部网络访问容器

通过端口映射的方式实现外部网络访问容器,即通过-p参数实现将容器的端口映射到外部端口。

四、总结

本文简单总结了单主机情况下容器网络的相关知识和使用方案,重点是使用方案,如果需要理解原理可以直接查阅CloudMan的相关教程。下一章总结跨主机容器网络。

Docker环境的CI/CD持续集成持续交付

Docker的最大好处之一是能够带来无缝的CI/CD流程;容器是Docker镜像的运行着的只读实例,更新容器仅仅需要更新镜像文件,然后从这个更新过的镜像重新部署容器。还有免费的工具可以监控镜像repository,并且在检测到镜像有更新的时候立即重新部署一个容器。但是,运行容器,创建以及更新镜像,这仍然是手动的。

将CI/CD的概念带入下一个级别是需要创建开发流水线,将软件交付流程里的所有步骤自动化。典型的单服务流水线包括如下基本步骤:

  • 构建 – 初始化构建过程,将源码转变为编译好的artifact,并且打包到Docker镜像里

  • 测试 – 使用支持你的框架的任意测试工具在Docker容器里运行单元测试。

  • 推送 – 将测试过的Docker镜像推送到Docker registry服务,比如Docker Hub上。

  • 部署 -从registry服务下载docker镜像到相应的staging/production Docker环境里。

  • 运行 – 从一个或者多个镜像里初始化容器或者服务

CI/CD的下一个逻辑上的扩展是通过webhook将开发代码repository完全集成到开发流水线上;这样,当事件,比如代码repository里发生代码提交或者merge时,就会自动执行构建-部署流水线流程。有了这样的集成,无论开发人员什么时候提交代码到repository里,几秒钟后,带有开发人员变更的Docker容器就会生成,之后就可以用于实时的集成测试了。

Emerging Technology Partners调研并且验证了当前市场上能够提供最全面的容器为中心的CI/CD特性的解决方案。我们的方案可以提供集成测试所需的完整的环境。每个build里UI测试或者性能测试都是测试的一部分,让大家可以完整测试任意提交或者PR。使用我们的解决方案,开发人员和测试任意可以快速发现regression,在staging前修复这些问题,加速了开发周期,并且节省了时间和精力。

如果你负责内部的应用程序开发团队,并且在测试或者发布频率上挣扎,那么可以给ETP电话,我们可以向你展示容器中心的CI/CD可以如何集成到你的开发流程里。

使用awk求指定列的最大值最小值

需求:一文件内容如下,求第一列的最大值和最小值

1 1220
2 1221
3 1222
3 1223
4 1224
5 1225
12 1226
12 1227
12 1228
12 1229

12 1230

命令如下

求最小值:

sed '/^$/d' test.txt|awk 'NR==1{min=$1;next}{min=min<$1?min:$1}END{print min}' 

求最大值:

sed '/^$/d' test.txt|awk 'NR==1{max=$1;next}{max=max>$1?max:$1}END{print max}' 

利用sed删除空行,利用awk筛选出最大值和最小值。

AWK 两个文件字段合并处理实例

一、概念解析

1、awk命令概念

$0 表示一个文本中的一行记录

$1...N 表示一行中的第 1...N 字段

FNR     The input record number in the current input file.  #已读入当前文件的记录数

NR      The total number of input records seen so far.      #已读入的总记录数

next    Stop processing the current input record. The next input record is

       read and processing starts over with the first pattern in the AWK

       program. If the end of the input data is reached, the END block(s),

       if any, are executed.

2、处理两个文本文件

执行处理顺序:

首先,对file1执行“NR==FNR{…}”第一个循环,建立哈希数组;第二步,执行“NR>FNR{…}”第二个循环,打印输出命令结果。

  • 一种是
awk 'NR==FNR{...}NR>FNR{...}' file1 file2 或 awk 'NR==FNR{...}NR!=FNR{...}' file1 file2
  • 另一种是
awk 'NR==FNR{...;next}{...}' file1 file2

二、处理两个文件实例

1、处理实例一

file1:

文件内容:

sina.com 52.5

sohu.com 42.5

baidu.com 35

file 2:

文件内容:

www.news.sina.com sina.com 80

www.over.sohu.com baidu.com 20

www.fa.baidu.com sohu.com 50

www.open.sina.com sina.com 60

www.sport.sohu.com sohu.com 70

www.xxx.sohu.com sohu.com 30

www.abc.sina.com sina.com 10

www.fa.baidu.com baidu.com 50

www.open.sina.com sina.com 60

www.over.sohu.com sohu.com 20


awk 'NR==FNR{a[$1]=$2;next}{print $0,a[$2]}' f1 f2

命令结果:

www.news.sina.com sina.com 80 52.5

www.over.sohu.com baidu.com 20 35

www.fa.baidu.com sohu.com 50 42.5

www.open.sina.com sina.com 60 52.5

www.sport.sohu.com sohu.com 70 42.5

www.xxx.sohu.com sohu.com 30 42.5

www.abc.sina.com sina.com 10 52.5

www.fa.baidu.com baidu.com 50 35

www.open.sina.com sina.com 60 52.5

www.over.sohu.com sohu.com 20 42.5

2、处理实例二

需要处理的同名字段可以在两个文件中行号不同的行,无需行号排序相对应,

命令结果的行顺序依据第二个文件中同名字段顺序输出。

f1

文件内容:

10020036 beijing

10050259 lanzhou

10045682 hefei

20130495 guangzhou

20981345 shenzhen

20984748 chengdu

20891376 changsha

f2

文件内容:

guangzhou 4.5

hefei 2.6

beijing 1.3

shenzhen 8.5

changsha 0.8

chengdu 2.0

lanzhou 2.4


awk 'NR==FNR{a[$2]=$1}NR>FNR{print a[$1],$0}' f1 f2

命令输出:

20130495 guangzhou 4.5

10045682 hefei 2.6

10020036 beijing 1.3

20981345 shenzhen 8.5

20891376 changsha 0.8

20984748 chengdu 2.0

10050259 lanzhou 2.4

awk如何指定多分隔符

awk的-F参数可以指定新的分隔符,有些时候可能需求指定多个分隔符,比如下面的内容

[root@N1 ~]# netstat -an | grep ESTAB 
udp        0      0 192.168.1.120:35570     212.47.249.141:123      ESTABLISHED
udp        0      0 192.168.1.120:55589     108.59.2.24:123         ESTABLISHED

如果需要取出源IP的话,一般大家会这样做,即做两次awk操作

[root@N1 ~]# netstat -an | grep ESTAB | awk  '{print $5}' | awk -F: '{print $1}'
108.59.2.24
212.47.249.141

其实呢,通过在awk中指定两个分隔符(空格和:),即可一次性的提取出源IP地址,在awk中支持多个分隔符的写法如下:

[root@N1 ~]# netstat -an | grep ESTAB | awk -F '[ :]+' '{print $6}'
108.59.2.24
212.47.249.141
#多一个加号表明将连续出现的分隔符当做一个来处理

注意:

在awk中,当分隔符指定为空字符串时,awk会将多个连续的空白看做一个单一的分隔符。此外,awk还会忽略开头和结尾处的空白。

apt-get安装软件时 需要依赖更低版本的依赖库 通用解决办法

比如ubuntu尝试安装sqlite3,

xda@xda-dt:~$ sudo apt-get install sqlite3 libsqlite3-0=3.7.9-2ubuntu1.1
Reading package lists... Done
Building dependency tree       
Reading state information... Done
libsqlite3-0 is already the newest version.
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:

The following packages have unmet dependencies:
 sqlite3 : Depends: libsqlite3-0 (= 3.7.9-2ubuntu1) but 3.7.9-2ubuntu1.1 is to be installed
E: Unable to correct problems, you have held broken packages.

会出现上面的问题。

方法1,使用aptitude 安装。

xda@xda-dt:~$ sudo aptitude install sqlite3
The following NEW packages will be installed:
  sqlite3{b} 
0 packages upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 26.9 kB of archives. After unpacking 174 kB will be used.
The following packages have unmet dependencies:
 sqlite3 : Depends: libsqlite3-0 (= 3.7.9-2ubuntu1) but 3.7.9-2ubuntu1.1 is installed.
The following actions will resolve these dependencies:

     Keep the following packages at their current version:
1)     sqlite3 [Not Installed]                            



Accept this solution? [Y/n/q/?] n
The following actions will resolve these dependencies:

     Downgrade the following packages:                                  
1)     libsqlite3-0 [3.7.9-2ubuntu1.1 (now) -> 3.7.9-2ubuntu1 (precise)]



Accept this solution? [Y/n/q/?] Y
The following packages will be DOWNGRADED:
  libsqlite3-0 
The following NEW packages will be installed:
  sqlite3 
0 packages upgraded, 1 newly installed, 1 downgraded, 0 to remove and 0 not upgraded.
Need to get 375 kB of archives. After unpacking 174 kB will be used.
Do you want to continue? [Y/n/?] Y
Get: 1 http://hk.archive.ubuntu.com/ubuntu/ precise/main libsqlite3-0 amd64 3.7.9-2ubuntu1 [348 kB]
Get: 2 http://hk.archive.ubuntu.com/ubuntu/ precise/main sqlite3 amd64 3.7.9-2ubuntu1 [26.9 kB]
Fetched 375 kB in 1s (306 kB/s)    
dpkg: warning: downgrading libsqlite3-0 from 3.7.9-2ubuntu1.1 to 3.7.9-2ubuntu1.
(Reading database ... 162912 files and directories currently installed.)
Preparing to replace libsqlite3-0 3.7.9-2ubuntu1.1 (using .../libsqlite3-0_3.7.9-2ubuntu1_amd64.deb) ...
Unpacking replacement libsqlite3-0 ...
Selecting previously unselected package sqlite3.
Unpacking sqlite3 (from .../sqlite3_3.7.9-2ubuntu1_amd64.deb) ...
Processing triggers for man-db ...
Setting up libsqlite3-0 (3.7.9-2ubuntu1) ...
Setting up sqlite3 (3.7.9-2ubuntu1) ...
Processing triggers for libc-bin ...
ldconfig deferred processing now taking place

xda@xda-dt:~$ sqlite3
SQLite version 3.7.9 2011-11-01 00:52:41
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .exit