使用Docker构建并测试Web应用程序

使用sinatra作为web框架,redis作为后方的数据库。

1.1 创建Sinatra 容器

dongli@ubuntu:~/Docker/Sinatra $ cat Dockerfile
FROM ubuntu
MAINTAINER Edgar Li " dongli@test.com"

RUN apt-get update
RUN apt-get -y install ruby ruby-dev build-essential redis-tools
RUN gem install --no-rdoc --no-ri sinatra json redis

RUN mkdir -p /opt/webapp

EXPOSE 4567

CMD ["/opt/webapp/bin/webapp"]

 # sudo docker build -t sinatra .

下载sinatra webapp 的应用程序
#wget --cut-dirs=3 -nH -r --no-parent  http://dockerbook.com/code/5/sinatra/webapp

dongli@ubuntu:~/Docker/Sinatra$  chmod +x $PWD/webapp/bin/webapp

dongli@ubuntu:~/Docker/Sinatra/webapp/bin$ ls
index.html   webapp

dongli@ubuntu:~/Docker/Sinatra$  sudo docker run -d -p 127.0.0.1::4567 --name webapp -v $PWD/webapp:/opt/webapp sinatra
6a9a0b7403a311592035b8315a819510dd459d15f0a8936e1597b7ace6fc883c

dongli@ubuntu:~/Docker/Sinatra$  sudo docker logs webapp
[2017-10-29 08:21:20] INFO  WEBrick 1.3.1
[2017-10-29 08:21:20] INFO  ruby 2.3.1 (2016-04-26) [x86_64-linux-gnu]
== Sinatra (v2.0.0) has taken the stage on 4567 for development with backup from WEBrick
[2017-10-29 08:21:20] INFO  WEBrick::HTTPServer#start: pid=1 port=4567

-f : tail -f
测试:
dongli@ubuntu:~/Docker/Sinatra/webapp$ curl -i -H 'Accept: application/json' -d 'name=Foo1&status=bar2'  http://127.0.0.1:32768/json
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Content-Length: 29
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Server: WEBrick/1.3.1 (Ruby/2.3.1/2016-04-26)
Date: Sun, 29 Oct 2017 08:34:38 GMT
Connection: Keep-Alive

{"name":"Foo","status":"bar"}

dongli@ubuntu:~/Docker/Sinatra$ sudo docker logs -f webapp
[2017-10-29 08:21:20] INFO  WEBrick 1.3.1
[2017-10-29 08:21:20] INFO  ruby 2.3.1 (2016-04-26) [x86_64-linux-gnu]
== Sinatra (v2.0.0) has taken the stage on 4567 for development with backup from WEBrick
[2017-10-29 08:21:20] INFO  WEBrick::HTTPServer#start: pid=1 port=4567
172.17.0.1 - - [29/Oct/2017:08:34:38 +0000] "POST /json HTTP/1.1" 200 29 0.0337
172.17.0.1 - - [29/Oct/2017:08:34:38 UTC] "POST /json HTTP/1.1" 200 29
- -> /json


1.2  构建Redis镜像和容器

构建容器的Redis镜像的Dockerfile:
dongli@ubuntu:~/Docker/redis$  cat Dockerfile
FROM ubuntu
MAINTAINER Edgar li " dongli@test.com"
RUN apt-get update
RUN apt-get -y install redis-server redis-tools
EXPOSE 6379
ENTRYPOINT ["/usr/bin/redis-server"]
CMD []
dongli@ubuntu:~/Docker/redis$


构建redis 镜像:
dongli@ubuntu:~/Docker/redis$  sudo docker build -t redis .
[sudo] password for dongli:
Sending build context to Docker daemon 2.048 kB
Step 1 : FROM ubuntu
 ---> ae81bbda2b6c
Step 2 : MAINTAINER Edgar li " dongli@test.com"
 ---> Running in d881ffa2a86b
 ---> d7bf03fc11f2
Removing intermediate container d881ffa2a86b
Step 3 : RUN apt-get update
 ---> Running in 88f0348ec5ef
Get:1  http://archive.ubuntu.com/ubuntu xenial InRelease [247 kB]
Get:2  http://archive.ubuntu.com/ubuntu xenial-updates InRelease [102 kB]
Get:3  http://archive.ubuntu.com/ubuntu xenial-security InRelease [102 kB]
Get:4  http://archive.ubuntu.com/ubuntu xenial/main Sources [1103 kB]
Get:5  http://archive.ubuntu.com/ubuntu xenial/restricted Sources [5179 B]
Get:6  http://archive.ubuntu.com/ubuntu xenial/universe Sources [9802 kB]
Get:7  http://archive.ubuntu.com/ubuntu xenial/main amd64 Packages [1558 kB]
Get:8  http://archive.ubuntu.com/ubuntu xenial/restricted amd64 Packages [14.1 kB]
Get:9  http://archive.ubuntu.com/ubuntu xenial/universe amd64 Packages [9827 kB]
Get:10  http://archive.ubuntu.com/ubuntu xenial-updates/main Sources [352 kB]
Get:11  http://archive.ubuntu.com/ubuntu xenial-updates/restricted Sources [3617 B]
Get:12  http://archive.ubuntu.com/ubuntu xenial-updates/universe Sources [221 kB]
Get:13  http://archive.ubuntu.com/ubuntu xenial-updates/main amd64 Packages [833 kB]
Get:14  http://archive.ubuntu.com/ubuntu xenial-updates/restricted amd64 Packages [13.7 kB]
Get:15  http://archive.ubuntu.com/ubuntu xenial-updates/universe amd64 Packages [692 kB]
Get:16  http://archive.ubuntu.com/ubuntu xenial-security/main Sources [121 kB]
Get:17  http://archive.ubuntu.com/ubuntu xenial-security/restricted Sources [2770 B]
Get:18  http://archive.ubuntu.com/ubuntu xenial-security/universe Sources [50.7 kB]
Get:19  http://archive.ubuntu.com/ubuntu xenial-security/main amd64 Packages [476 kB]
Get:20  http://archive.ubuntu.com/ubuntu xenial-security/restricted amd64 Packages [12.9 kB]
Get:21  http://archive.ubuntu.com/ubuntu xenial-security/universe amd64 Packages [220 kB]
Fetched 25.8 MB in 2min 47s (154 kB/s)
Reading package lists...
 ---> af8251a47910
Removing intermediate container 88f0348ec5ef
Step 4 : RUN apt-get -y install redis-server redis-tools
 ---> Running in c97e4dba51d7
Reading package lists...
Building dependency tree...
Reading state information...
The following additional packages will be installed:
  libjemalloc1
Suggested packages:
  ruby-redis
The following NEW packages will be installed:
  libjemalloc1 redis-server redis-tools
0 upgraded, 3 newly installed, 0 to remove and 38 not upgraded.
Need to get 517 kB of archives.
After this operation, 1505 kB of additional disk space will be used.
Get:1  http://archive.ubuntu.com/ubuntu xenial/universe amd64 libjemalloc1 amd64 3.6.0-9ubuntu1 [78.9 kB]
Get:2  http://archive.ubuntu.com/ubuntu xenial/universe amd64 redis-tools amd64 2:3.0.6-1 [95.3 kB]
Get:3  http://archive.ubuntu.com/ubuntu xenial/universe amd64 redis-server amd64 2:3.0.6-1 [343 kB]
debconf: delaying package configuration, since apt-utils is not installed
Fetched 517 kB in 3s (141 kB/s)
Selecting previously unselected package libjemalloc1.
(Reading database ... 7256 files and directories currently installed.)
Preparing to unpack .../libjemalloc1_3.6.0-9ubuntu1_amd64.deb ...
Unpacking libjemalloc1 (3.6.0-9ubuntu1) ...
Selecting previously unselected package redis-tools.
Preparing to unpack .../redis-tools_2%3a3.0.6-1_amd64.deb ...
Unpacking redis-tools (2:3.0.6-1) ...
Selecting previously unselected package redis-server.
Preparing to unpack .../redis-server_2%3a3.0.6-1_amd64.deb ...
Unpacking redis-server (2:3.0.6-1) ...
Processing triggers for libc-bin (2.23-0ubuntu3) ...
Processing triggers for systemd (229-4ubuntu7) ...
Setting up libjemalloc1 (3.6.0-9ubuntu1) ...
Setting up redis-tools (2:3.0.6-1) ...
Setting up redis-server (2:3.0.6-1) ...
invoke-rc.d: could not determine current runlevel
invoke-rc.d: policy-rc.d denied execution of start.
Processing triggers for libc-bin (2.23-0ubuntu3) ...
Processing triggers for systemd (229-4ubuntu7) ...
 ---> fc09e8f1a5c0
Removing intermediate container c97e4dba51d7
Step 5 : EXPOSE 6379
 ---> Running in ed5e1a3e4ea5
 ---> e4ec8c27ce8c
Removing intermediate container ed5e1a3e4ea5
Step 6 : ENTRYPOINT /usr/bin/redis-server
 ---> Running in 23e00b6b9c1a
 ---> a8f9dbc36c96
Removing intermediate container 23e00b6b9c1a
Step 7 : CMD
 ---> Running in 8ea0fbff8d87
 ---> f4f39de16993
Removing intermediate container 8ea0fbff8d87
Successfully built f4f39de16993
dongli@ubuntu:~/Docker/redis$

启动redis容器:
dongli@ubuntu:~/Docker/redis$ sudo docker run -d -p 6379 --name redis redis
b3c8a62211e8447fe35cd82502e4602b571bca4d0dfbcc0f96cacc72b8171f0b

// 安装 redis-tools 在宿主主机上。
dongli@ubuntu:~/Docker/redis$ sudo apt-get -y install redis-tools
//验证 redis服务器工作正常
dongli@ubuntu:~/Docker/redis$ redis-cli -h 127.0.0.1 -p 32769
127.0.0.1:32769>

1.3 连接到容器

第一种方法,涉及Docker自己的网络栈, Docker 容器公开端口绑定到本地网络接口。再启动容器的时候指定的本地网络IP:port 和docker 端口的对应关系。
第二种, 内部网络:
    Docker service 启动后出现新的网络接口 docker0.
     dongli@ubuntu :~$ ifconfig docker0
docker0   Link encap:Ethernet  HWaddr 02:42:6b:4b:fe:66
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
Docker0 符合RFC1918的私有IP。默认使用172.17.x.x 作为子网地址。如果有人占用了,在172.16 ~172.30 范围内尝试。Docker0 也是所有docker的网关。
docker0 是个虚拟的以太网桥,连接容器和本地宿主网络。启动一个容器,就会创建一组互联的网络接口
     dongli@ubuntu :~$ brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.02426b4bfe66       no              vethb232e5e
virbr0          8000.5254009cf352       yes             virbr0-nic
一端  vethb232e5e 宿主机的一个端口, 另外一端是容器的eth0接口。

root@d6827c0c126b:/# ip a show eth0
10:  eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet  172.17.0.3/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe11:3/64 scope link
       valid_lft forever preferred_lft forever

traceroute to baidu.com (111.13.101.208), 30 hops max, 60 byte packets
 1   172.17.0.1 (172.17.0.1)  0.068 ms  0.032 ms  0.024 ms
 2  192.168.126.2 (192.168.126.2)  0.225 ms  0.165 ms  0.215 ms^C

command:  sudo iptables -t net -L -n 产看  IPtable 规则。 

dongli@ubuntu:~$ sudo iptables -t nat -L -n
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0           !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0
RETURN     all  --  192.168.122.0/24     224.0.0.0/24
RETURN     all  --  192.168.122.0/24     255.255.255.255
MASQUERADE  tcp  --  192.168.122.0/24    !192.168.122.0/24     masq ports: 1024-65535
MASQUERADE  udp  --  192.168.122.0/24    !192.168.122.0/24     masq ports: 1024-65535
MASQUERADE  all  --  192.168.122.0/24    !192.168.122.0/24
MASQUERADE  tcp  --  172.17.0.2           172.17.0.2           tcp dpt:6379

Chain DOCKER (2 references)
target     prot opt source               destination
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:32768 to:172.17.0.2:6379
容器默认是不能访问, 必须要指定端口。

1.4 连接到Redis 容器
 sudo docker inspect redis

查看redie容器活动的IP:
sudo docker inspect -f '{{.NetworkSettings.IPAddress}}' redis
dongli@ubuntu:~$ sudo docker inspect -f '{{.NetworkSettings.IPAddress}}' redis
172.17.0.2

测试redis
dongli@ubuntu:~$ redis-cli -h 172.17.0.2
172.17.0.2:6379>

问题: docker 重启后IP会变

Docker link 功能将容器连接起来。 

1.5 让 Docker容器互联

建立一个新的Redis 容器 ( 注意: 这里没有指定端口)  连接后父容器可以直接访问子容器。也只有使用--link标志连接到这个容器的容器才能连接到这个端口。容器端口不需要对宿主主机公开。
dongli@ubuntu:~$ sudo docker run -d --name redis redis
244d27f44982964cbd4fdafb3cc630624f03f64b8acdc319333be778d8e9ff19

建立一个webapp容器
dongli@ubuntu:~/Docker$ ls
redis  sample  Sinatra  static_web  test  test2
dongli@ubuntu:~/Docker$ cd Sinatra/
dongli@ubuntu:~/Docker/Sinatra$ sudo docker run -p 4567 --name webapp --link redis:db -t -i -v $PWD/webapp:/opt/webapp sinatra /bin/bash
 --link 标准创建了两个容器间的父子连接。两个参数:1.要连接的容器的名字, 2 连接后容器的名字。 要连接到redis,使用db作为别名。 让父容器访问子容器。
(处于安全考虑,可以强制Dokcer只允许有连接的容器间互相通信。 需要在启动Docker守护进程时加上 --ice=false,关闭所有没有连接的容器间的通信。
可以将多个web应用程序连接到redis容器。(同一台宿主)

root@a70a6628bd08:/# cat /etc/hosts
172.17.0.3      a70a6628bd08  // webapp
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.2      db 244d27f44982 redis  //redis IP 连接指令建立的。 如果redis重启, IP会自动更新。

root@a70a6628bd08:/# env  //注意DB开头的参数
HOSTNAME=a70a6628bd08
DB_NAME=/webapp/db
DB_PORT_6379_TCP_PORT=6379
TERM=xterm
DB_PORT=tcp://172.17.0.2:6379
DB_PORT_6379_TCP=tcp://172.17.0.2:6379
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;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
PWD=/
DB_PORT_6379_TCP_ADDR=172.17.0.2
DB_PORT_6379_TCP_PROTO=tcp
SHLVL=1
HOME=/root
_=/usr/bin/env


 1.6 使用容器连接通信
       1. 使用环境变量里边的信息
            
       2. 使用DNS和/etc/hosts 信息
app.br:
require "rubygems"
require "sinatra"
require "json"
require "redis"

class App < Sinatra::Application

      redis = Redis.new(:host => 'db', :port => '6379')

      set :bind, '0.0.0.0'

      get '/' do
        "<h1>DockerBook Test Redis-enabled Sinatra app</h1>"
      end

      get '/json' do
        params = redis.get "params"
        params.to_json
      end

      post '/json/?' do
        redis.set "params", [params].to_json
        params.to_json
      end
end

        测试:
dongli@ubuntu:~/Docker/Sinatra/webapp/lib$ curl -i -H 'Accept: application/json' -d 'name=Foo1&status=bar2'  http://localhost:32768/json
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Content-Length: 31
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Server: WEBrick/1.3.1 (Ruby/2.3.1/2016-04-26)
Date: Fri, 03 Nov 2017 14:33:14 GMT
Connection: Keep-Alive

{"name":"Foo1","status":"bar2"} dongli@ubuntu:~/Docker/Sinatra/webapp/lib$
dongli@ubuntu:~/Docker/Sinatra/webapp/lib$ curl -i  http://localhost:32768/json
HTTP/1.1 200 OK
Content-Type: text/html;charset=utf-8
Content-Length: 43
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Server: WEBrick/1.3.1 (Ruby/2.3.1/2016-04-26)
Date: Fri, 03 Nov 2017 14:33:23 GMT
Connection: Keep-Alive

"[{\"name\":\"Foo1\",\"status\":\"bar2\"}]" dongli@ubuntu:~/Docker/Sinatra/webapp/lib$

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐