5.2.1 构建 Sinatra 应用程序

  1. 创建目录

image.png

  1. Dockerfile

image.png

  1. FROM ubuntu:14.04
  2. MAINTAINER James Turnbull "james@example.com"
  3. ENV REFRESHED_AT 2014-06-01
  4. RUN apt-get update -yqq && apt-get -yqq install ruby ruby-dev build-essential redis-tools
  5. RUN gem install --no-rdoc --no-ri sinatra json redis
  6. RUN mkdir -p /opt/webapp
  7. EXPOSE 4567
  8. CMD ["/opt/webapp/bin/webapp"]
  1. 构建
  1. $ sudo docker build -t jdxj/sinatra .
  2. [sudo] jdxj 的密码:
  3. Sending build context to Docker daemon 2.048kB
  4. Step 1/8 : FROM ubuntu:14.04
  5. ---> df043b4f0cf1
  6. Step 2/8 : MAINTAINER James Turnbull "james@example.com"
  7. ---> Using cache
  8. ...

5.2.2 创建 Sinatra 容器

image.png

启动:

  1. $ sudo docker run -d -p 4567 --name webapp -v $PWD/webapp:/opt/webapp jdxj/sinatra
  2. 0f40c6838fa3803962ccd8383ca00af91993cd0532e97aa16a9a8e2d0ca6cb70

5.2.3 扩展 Sinatra 应用程序来使用 Redis

1. 升级我们的 Sinatra 应用程序

image.png

2. 构建 Redis 数据库镜像

  • Dockerfile

image.png

  • 构建
  1. $ sudo docker build -t jdxj/redis .
  2. Sending build context to Docker daemon 2.048kB
  3. Step 1/7 : FROM ubuntu:18.04
  4. ---> 2c047404e52d
  5. Step 2/7 : LABEL maintainer="james@example.com"
  6. ---> Using cache
  7. ---> 0bb3ff33e238
  8. ...
  • 启动
  1. $ sudo docker run -d -p 6379 --name redis_test jdxj/redis
  2. 0b786164c7f29fc6a47b21289758934c280664ddedddfa39eae167b8ab5cd1f3

5.2.4 将 Sinatra 应用程序连接到 Redis 容器

连接容器有几种方法:

  • Docker 的内部网络 (不推荐)
  • Docker 1.9 及之后, 可以使用 Docker Networking 以及 docker network 命令
  • Docker 链接 (Docker link) (1.9 之前推荐)

Docker Networking 和 Docker link 的区别:

image.png

5.2.5 Docker 内部连网

在安装 Docker 时, 会创建一个新的网络接口 docker0. 每个 Docker 容器都会在这个接口上分配一个 IP 地址.

docker0:

  1. $ ip a show docker0
  2. 3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
  3. link/ether 02:42:b4:dc:07:fa brd ff:ff:ff:ff:ff:ff
  4. inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
  5. valid_lft forever preferred_lft forever
  6. inet6 fe80::42:b4ff:fedc:7fa/64 scope link
  7. valid_lft forever preferred_lft forever
  • 内网地址范围: 172.16.0.0 - 172.31.255.255
  • docker0 的分配范围: 172.16~172.30
  • docker0 本身地址为: 172.17.0.1

veth:

image.png

image.png

image.png

image.png

Docker 网络还有另一个部分配置才能允许建立连接:

  • 防火墙规则
  • NAT 配置

这些配置允许 Docker 在宿主网络和容器间路由.

查看宿主机上的 IPTables NAT 配置:

  1. $ sudo iptables -t nat -L -n
  2. [sudo] jdxj 的密码:
  3. Chain PREROUTING (policy ACCEPT)
  4. target prot opt source destination
  5. DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
  6. Chain INPUT (policy ACCEPT)
  7. target prot opt source destination
  8. Chain OUTPUT (policy ACCEPT)
  9. target prot opt source destination
  10. DOCKER all -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
  11. Chain POSTROUTING (policy ACCEPT)
  12. target prot opt source destination
  13. MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
  14. MASQUERADE all -- 172.18.0.0/16 0.0.0.0/0
  15. MASQUERADE tcp -- 172.17.0.3 172.17.0.3 tcp dpt:80
  16. MASQUERADE tcp -- 172.17.0.4 172.17.0.4 tcp dpt:4567
  17. MASQUERADE tcp -- 172.17.0.5 172.17.0.5 tcp dpt:6379
  18. Chain DOCKER (2 references)
  19. target prot opt source destination
  20. RETURN all -- 0.0.0.0/0 0.0.0.0/0
  21. RETURN all -- 0.0.0.0/0 0.0.0.0/0
  22. DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49154 to:172.17.0.3:80
  23. DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49155 to:172.17.0.4:4567
  24. DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49156 to:172.17.0.5:6379

网络相关阅读:

Redis 容器的网络

  1. $ sudo docker inspect redis_test
  2. ...
  3. "NetworkSettings": {
  4. "Bridge": "",
  5. "SandboxID": "ad6246f985bdcbd0aa15ff5be19a013b28a962b3a3c3d744682719b32346a7b9",
  6. "HairpinMode": false,
  7. "LinkLocalIPv6Address": "",
  8. "LinkLocalIPv6PrefixLen": 0,
  9. "Ports": {
  10. "6379/tcp": [
  11. {
  12. "HostIp": "0.0.0.0",
  13. "HostPort": "49157"
  14. }
  15. ]
  16. },
  17. "SandboxKey": "/var/run/docker/netns/ad6246f985bd",
  18. "SecondaryIPAddresses": null,
  19. "SecondaryIPv6Addresses": null,
  20. "EndpointID": "ee4ecd535e5d2fd34d9a7d79843c774647860efa100afb937dd7098e7e6b7c3f",
  21. "Gateway": "172.17.0.1",
  22. "GlobalIPv6Address": "",
  23. "GlobalIPv6PrefixLen": 0,
  24. "IPAddress": "172.17.0.5",
  25. "IPPrefixLen": 16,
  26. "IPv6Gateway": "",
  27. "MacAddress": "02:42:ac:11:00:05",
  28. "Networks": {
  29. "bridge": {
  30. "IPAMConfig": null,
  31. "Links": null,
  32. "Aliases": null,
  33. "NetworkID": "3c81845502810addebbfe15bc6e7db9309f5cf84acd4be2b9215a563c9f659c9",
  34. "EndpointID": "ee4ecd535e5d2fd34d9a7d79843c774647860efa100afb937dd7098e7e6b7c3f",
  35. "Gateway": "172.17.0.1",
  36. "IPAddress": "172.17.0.5",
  37. "IPPrefixLen": 16,
  38. "IPv6Gateway": "",
  39. "GlobalIPv6Address": "",
  40. "GlobalIPv6PrefixLen": 0,
  41. "MacAddress": "02:42:ac:11:00:05",
  42. "DriverOpts": null
  43. }
  44. }
  45. }
  46. ...

这种容器互联方案有两个问题:

  • 应用程序要对 Redis 容器 IP 地址做硬编码
  • 重启容器后 Redis 容器 IP 会变化

5.2.6 Docker Networking

image.png

  1. 创建 Docker 网络
    1. 桥接网络
  1. $ sudo docker network create app
  2. [sudo] jdxj 的密码:
  3. de1722dc3cb119e39338fa56be68674df1b8d230ee89821f7ed87a4713766a68

查看新创建的网络:

  1. $ sudo docker network inspect app
  2. [
  3. {
  4. "Name": "app",
  5. "Id": "de1722dc3cb119e39338fa56be68674df1b8d230ee89821f7ed87a4713766a68",
  6. "Created": "2021-01-15T15:09:39.40914087+08:00",
  7. "Scope": "local",
  8. "Driver": "bridge",
  9. "EnableIPv6": false,
  10. "IPAM": {
  11. "Driver": "default",
  12. "Options": {},
  13. "Config": [
  14. {
  15. "Subnet": "172.19.0.0/16",
  16. "Gateway": "172.19.0.1"
  17. }
  18. ]
  19. },
  20. "Internal": false,
  21. "Attachable": false,
  22. "Ingress": false,
  23. "ConfigFrom": {
  24. "Network": ""
  25. },
  26. "ConfigOnly": false,
  27. "Containers": {},
  28. "Options": {},
  29. "Labels": {}
  30. }
  31. ]

overlay 网络允许跨多台宿主机进行通信:

列出所有网络:

  1. $ sudo docker network ls
  2. NETWORK ID NAME DRIVER SCOPE
  3. de1722dc3cb1 app bridge local
  4. 3c8184550281 bridge bridge local
  5. 0c2e0f70fb87 host host local
  6. 52b9fca4051b localnet bridge local
  7. aa57e57f4d0c none null local
  1. 向 app 网络中添加容器

redis:

  1. $ sudo docker run -d --net=app --name db jdxj/redis
  2. 172eb42594462ec1c22f0b818edd5c1f388a8c5a1ef628bfad76ce88bd858ba1

webapp:

  1. $ sudo docker run -p 4567 --net=app --name webapp -t -i -v $PWD/webapp:/opt/webapp jdxj/sinatra /bin/bash
  2. root@4623e133fbb8:/#

查看 hosts:

  1. root@4623e133fbb8:/# cat /etc/hosts
  2. 127.0.0.1 localhost
  3. ::1 localhost ip6-localhost ip6-loopback
  4. fe00::0 ip6-localnet
  5. ff00::0 ip6-mcastprefix
  6. ff02::1 ip6-allnodes
  7. ff02::2 ip6-allrouters
  8. 172.19.0.3 4623e133fbb8
  9. root@4623e133fbb8:/#

1. 将已有容器连接到 Docker 网络

  1. $ sudo docker network connect app db2

断开:

  1. $ sudo docker network disconnect app db2

2. 通过 Docker 链接连接容器

1.9版本之前的选择.

低于1.9版本的使用:

  • 只能工作于同一台 Docker 宿主机中
  1. # 容器名:链接名
  2. $ sudo docker run -p 4567 --name webapp --link redis:db -t -i \
  3. -v $PWD/webapp_redis:/opt/webapp jamtur01/sinatra /bin/bash

5.2.7 使用容器连接来通信

有两种方法可以让应用程序连接到 Redis.

  • 环境变量
  • DNS 和 /etc/hosts 信息

环境变量:

image.png

DNS:

image.png

5.2.8 连接容器小结