Redis容器应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ cat Dockerfile 

FROM ubuntu:14.04
MAINTAINER Acqua Young "acqua@gmail.com"
ENV REFRESHED_AT 2018-01-20

RUN apt-get update
RUN apt-get -y install redis-server redis-tools

EXPOSE 6379
ENTRYPOINT ["/usr/bin/redis-server"]
CMD []

$ docker build -t acqua/redis .
$ docker run -d -p 6379 --name redis acqua/redis

Docker默认会把公开的端口绑定到所有的网络接口上,localhost或127.0.0.1来访问。

容器互连

1
2
3
4
5
6
7
$ docker run -d --name redis acqua/redis
未指定端口

$ docker run -p 4567 \
--name webapp --link redis:db -t -i \
-v /root/sinatra/webapp:/opt/webapp acqua/sinatra \
/bin/bash

–link参数创建了两个容器间的父子连接。该参数需指定:一个是要连接的容器名字,另一个是连接后容器的别名。示例中,把新容器连接到redis容器,并使用db作为别名。别名可以访问公开信息,而无须关注底层容器的名字。连接让父容器能访问子容器,并且把子容器的一些连接细节分享给父容器,这些细节有助于配置应用程序并使用这个连接。

在启动Redis容器时,并没有使用-p公开Redis的端口,因为不需要。通过把容器连接在一起,可以让父容器直接访问任意子容器的公开端口(如,父容器webapp可以连接到子容器redis的6379端口)。更好的是只有使用–link参数连接到这个容器的容器才能连接到这个端口,容器的端口不需要对本地宿主机公开。

出于安全考虑,可以强制Docker只允许有连接的容器之间互相通信,需要在启动Docker守护进程时加上--icc=false标志,关闭所有没有连接的容器间的通信。

也可以把多个容器连接在一起。如想让这个Redis实例服务于多个Web应用程序,可以把每个Web应用程序的容器和同一个redis容器连接在一起:

1
2
3
4
$ docker run -p 4567 --name webapp2 --link redis:db ...
$ docker run -p 4567 --name webapp3 --link redis:db ...

被连接的容器必须运行在同一个Docker宿主机上,不同Docker宿主机上运行的容器无法连接。

Docker在父容器中2个地方写入了连接信息:

  • /etc/hosts
1
2
3
4
5
6
7
8
9
10
11
$ cat  /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.4 db bb4ca80d2586 redis
172.17.0.3 004026a0d810

容器的主机名也可以不是其ID的一部分,可以在执行`docker run`命令时使用`-h`或`--hostname`参数指定容器的主机名。
  • 包含连接信息的环境变量中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
root@004026a0d810:/# env
HOSTNAME=004026a0d810
DB_NAME=/webapp/db
DB_PORT_6379_TCP_PORT=6379
TERM=xterm
DB_PORT=tcp://172.17.0.4:6379
DB_PORT_6379_TCP=tcp://172.17.0.4:6379
OLDPWD=/opt
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;
......
DB_ENV_REFRESHED_AT=2018-01-20
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
REFRESHED_AT=2018-01-19
PWD=/
DB_PORT_6379_TCP_ADDR=172.17.0.4
DB_PORT_6379_TCP_PROTO=tcp
SHLVL=1
HOME=/root
LESSOPEN=| /usr/bin/lesspipe %s
LESSCLOSE=/usr/bin/lesspipe %s %s
_=/usr/bin/env

Docker在连接webapp和redis容器时,自动创建了以DB开头的环境变量,自动创建的环境变量包含以下信息:

  • 子容器的名字
  • 容器里运行的服务所使用的协议、IP和端口号
  • 容器里运行的不同服务所指定的协议、IP和端口号
  • 容器里由Docker设置的环境变量的值

使用容器连接来通信的方式

  • 使用环境变量 (发现服务的方法)
  • 使用DNS和/etc/hosts信息

Jekyll & Apache应用

Dockerfiles

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ docker run -v /root/jekyll/acqua_blog:/data/ --name acqua_blog acqua/jekll

Configuration file: /data/_config.yml
Source: /data
Destination: /var/www/html
Generating...
done.
Auto-regeneration: disabled. Use --watch to enable.

$ docker run -d -P --volumes-from acqua_blog acqua/apache
$ docker port 15a03f8210c8 80
0.0.0.0:32775

$ docker start acqua_blog
$ docker logs acqua_blog

因为共享卷会自动更新,不需要更新或重启Apache容器。

备份Jekyll卷

1
2
3
4
5
6
7
8
$ docker run --rm --volumes-from acqua_blog \
-v $(pwd):/backup ubuntu \
tar cvf /backup/acqua_blog.tar /var/www/html

--rm参数会在容器(Ubuntu)的进程运行完毕后自动删除,适用容器用完即扔的场景。

$ ls
acqua_blog acqua_blog.tar Dockerfile

Java应用

Dockerfiles

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ docker build -t acqua/java .
$ docker run -t -i --name sample acqua/java \
https://tomcat.apache.org/tomcat-7.0-doc/appdev/sample/sample.war

$ docker inspect -f '{{ .Config.Volumes }}' sample
map[/var/lib/tomcat7/webapps/:{}]

$ docker build -t acqua/tomcat7 .
$ docker run --name sample_app --volumes-from sample \
-d -P acqua/tomcat7

$ docker port sample_app 8080
0.0.0.0:32768

http://x.x.x.x:32768/sample/

Reference
The Docker Book