Merge pull request #291 from khs1994/master

pull/295/merge
Baohua Yang 2017-12-10 15:09:26 +08:00 committed by GitHub
commit e6291d57f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 101 additions and 327 deletions

View File

@ -10,8 +10,9 @@
"plugins": [
"-livereload",
"image-captions",
"github-buttons",
"page-treeview"
"github",
"page-treeview",
"editlink"
],
"pluginsConfig": {
"image-captions": {
@ -20,13 +21,12 @@
},
"caption": "图 _PAGE_LEVEL_._PAGE_IMAGE_NUMBER_ - _CAPTION_"
},
"github-buttons": {
"buttons": [{
"user": "yeasy",
"repo": "docker_practice",
"type": "star",
"size": "small"
}]
"github": {
"url": "https://github.com/yeasy/docker_practice"
},
"editlink": {
"base": "https://github.com/yeasy/docker_practice/blob/master/",
"label": "编辑本页"
},
"page-treeview": {
"copyright": "Copyright © yeasy",

View File

@ -4,6 +4,10 @@
* 0.9-rc3: 2017-12-20
* 精简示例代码
* 调整目录结构
* 0.9-rc2: 2017-12-10
* 增加 Docker 中文资源链接

View File

@ -2,9 +2,9 @@
[![](https://img.shields.io/github/stars/yeasy/docker_practice.svg?style=social&label=Stars)](https://github.com/yeasy/docker_practice) [![](https://img.shields.io/docker/pulls/yeasy/docker_practice.svg)](https://store.docker.com/community/images/yeasy/docker_practice) [![](https://travis-ci.org/yeasy/docker_practice.svg?branch=master)](https://travis-ci.org/yeasy/docker_practice) [![](https://img.shields.io/github/release/yeasy/docker_practice/all.svg)](https://github.com/yeasy/docker_practice/releases) [![](https://badges.gitter.im/docker_practice/Lobby.svg)](https://gitter.im/docker_practice/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
0.9-rc1(2017-11-29)
0.9-rc2(2017-12-09)
*修订说明:本书内容将基于 Docker CE v17.x 进行重新修订,计划 2017 年底发布 0.9.0 版本。旧版本Docker 1.13-)内容,请阅读 [docker-legacy](https://github.com/yeasy/docker_practice/tree/docker-legacy) 分支的内容。*
*修订说明:本书内容将基于 Docker CE v17.MM 进行重新修订,计划 2017 年底发布 0.9.0 版本。旧版本Docker 1.13-)内容,请阅读 [docker-legacy](https://github.com/yeasy/docker_practice/tree/docker-legacy) 分支的内容。*
[Docker](http://www.docker.com) 是个划时代的开源项目,它彻底释放了计算虚拟化的威力,极大提高了应用的运行效率,降低了云计算资源供应的成本!使用 Docker可以让应用的部署、测试和分发都变得前所未有的高效和轻松
@ -18,7 +18,7 @@
* pdf 版本 [下载](https://www.gitbook.com/download/pdf/book/yeasy/docker_practice)
* epub 版本 [下载](https://www.gitbook.com/download/epub/book/yeasy/docker_practice)
Docker 自身仍在快速发展中,生态环境也在蓬勃成长。建议初学者使用最新版的 Docker (v17.x) 进行学习实践。欢迎 [参与维护项目](CONTRIBUTING.md)。
Docker 自身仍在快速发展中,生态环境也在蓬勃成长。建议初学者使用最新版的 Docker (v17.MM) 进行学习实践。欢迎 [参与维护项目](CONTRIBUTING.md)。
* [修订记录](CHANGELOG.md)
* [贡献者名单](https://github.com/yeasy/docker_practice/graphs/contributors)

View File

@ -57,9 +57,9 @@
* [使用网络](network/README.md)
* [外部访问容器](network/port_mapping.md)
* [容器互联](network/linking.md)
* [配置 DNS](network/dns.md)
* [高级网络配置](advanced_network/README.md)
* [快速配置指南](advanced_network/quick_guide.md)
* [配置 DNS](advanced_network/dns.md)
* [容器访问控制](advanced_network/access_control.md)
* [端口映射实现](advanced_network/port_mapping.md)
* [配置 docker0 网桥](advanced_network/docker0.md)

View File

@ -10,8 +10,9 @@
"plugins": [
"-livereload",
"image-captions",
"github-buttons",
"page-treeview"
"github",
"page-treeview",
"editlink"
],
"pluginsConfig": {
"image-captions": {
@ -20,13 +21,12 @@
},
"caption": "图 _PAGE_LEVEL_._PAGE_IMAGE_NUMBER_ - _CAPTION_"
},
"github-buttons": {
"buttons": [{
"user": "yeasy",
"repo": "docker_practice",
"type": "star",
"size": "small"
}]
"github": {
"url": "https://github.com/yeasy/docker_practice"
},
"editlink": {
"base": "https://github.com/yeasy/docker_practice/blob/master/",
"label": "编辑本页"
},
"page-treeview": {
"copyright": "Copyright © yeasy",

View File

@ -8,3 +8,4 @@
阿里云容器服务提供了高性能、可伸缩的容器应用管理服务,支持在一组云服务器上通过 Docker 容器来进行应用生命周期管理。容器服务极大简化了用户对容器管理集群的搭建工作,无缝整合了阿里云虚拟化、存储、网络和安全能力。容器服务提供了多种应用发布方式和流水线般的持续交付能力,原生支持微服务架构,助力用户无缝上云和跨云管理。
![](https://img.alicdn.com/tps/TB10yjtPpXXXXacXXXXXXXXXXXX-1531-1140.png)

View File

@ -7,3 +7,5 @@
具体包括云服务器、云存储、云数据库和弹性 web 引擎等基础云服务腾讯云分析MTA、腾讯云推送信鸽等腾讯整体大数据能力以及 QQ互联、QQ 空间、微云、微社区等云端链接社交体系。这些正是腾讯云可以提供给这个行业的差异化优势,造就了可支持各种互联网使用场景的高品质的腾讯云技术平台。
腾讯云容器服务是高度可扩展的高性能容器管理服务用户可以在托管的云服务器实例集群上轻松运行应用程序。使用该服务将无需安装、运维、扩展用户的集群管理基础设施只需进行简单的API调用便可启动和停止Docker应用程序查询集群的完整状态以及使用各种云服务。用户可以根据用户的资源需求和可用性要求在用户的集群中安排容器的置放满足业务或应用程序的特定要求。
![](https://mc.qcloudimg.com/static/img/0581dbeb97c869bbe6e62025dbc592d7/image.png)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,5 @@
FROM python:3.6-alpine
ADD . /code
WORKDIR /code
RUN pip install redis flask
CMD ["python", "app.py"]

13
compose/demo/app/app.py Normal file
View File

@ -0,0 +1,13 @@
from flask import Flask
from redis import Redis
app = Flask(__name__)
redis = Redis(host='redis', port=6379)
@app.route('/')
def hello():
count = redis.incr('hits')
return 'Hello World! 该页面已被访问 {} 次。\n'.format(count)
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)

View File

@ -0,0 +1,10 @@
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"

View File

@ -1,29 +0,0 @@
version: "3"
services:
weba:
build: ./web
expose:
- 80
webb:
build: ./web
expose:
- 80
webc:
build: ./web
expose:
- 80
haproxy:
image: haproxy:latest
volumes:
- ./haproxy:/haproxy-override
- ./haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
ports:
- "80:80"
- "70:70"
expose:
- "80"
- "70"

View File

@ -1,32 +0,0 @@
global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
listen stats
bind 0.0.0.0:70
stats enable
stats uri /
frontend balancer
bind 0.0.0.0:80
mode http
default_backend web_backends
backend web_backends
mode http
option forwardfor
balance roundrobin
server weba weba:80 check
server webb webb:80 check
server webc webc:80 check
option httpchk GET /
http-check expect status 200

View File

@ -1,5 +0,0 @@
FROM python:2.7
WORKDIR /code
ADD . /code
EXPOSE 80
CMD python index.py

View File

@ -1,68 +0,0 @@
#!/usr/bin/python
#authors: yeasy.github.com
#date: 2013-07-05
import sys
import BaseHTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
import socket
import fcntl
import struct
import pickle
from datetime import datetime
from collections import OrderedDict
class HandlerClass(SimpleHTTPRequestHandler):
def get_ip_address(self,ifname):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
return socket.inet_ntoa(fcntl.ioctl(
s.fileno(),
0x8915, # SIOCGIFADDR
struct.pack('256s', ifname[:15])
)[20:24])
def log_message(self, format, *args):
if len(args) < 3 or "200" not in args[1]:
return
try:
request = pickle.load(open("pickle_data.txt","r"))
except:
request=OrderedDict()
time_now = datetime.now()
ts = time_now.strftime('%Y-%m-%d %H:%M:%S')
server = self.get_ip_address('eth0')
host=self.address_string()
addr_pair = (host,server)
if addr_pair not in request:
request[addr_pair]=[1,ts]
else:
num = request[addr_pair][0]+1
del request[addr_pair]
request[addr_pair]=[num,ts]
file=open("index.html", "w")
file.write("<!DOCTYPE html> <html> <body><center><h1><font color=\"blue\" face=\"Georgia, Arial\" size=8><em>HA</em></font> Webpage Visit Results</h1></center>")
for pair in request:
if pair[0] == host:
guest = "LOCAL: "+pair[0]
else:
guest = pair[0]
if (time_now-datetime.strptime(request[pair][1],'%Y-%m-%d %H:%M:%S')).seconds < 3:
file.write("<p style=\"font-size:150%\" >#"+ str(request[pair][1]) +": <font color=\"red\">"+str(request[pair][0])+ "</font> requests " + "from &lt<font color=\"blue\">"+guest+"</font>&gt to WebServer &lt<font color=\"blue\">"+pair[1]+"</font>&gt</p>")
else:
file.write("<p style=\"font-size:150%\" >#"+ str(request[pair][1]) +": <font color=\"maroon\">"+str(request[pair][0])+ "</font> requests " + "from &lt<font color=\"navy\">"+guest+"</font>&gt to WebServer &lt<font color=\"navy\">"+pair[1]+"</font>&gt</p>")
file.write("</body> </html>")
file.close()
pickle.dump(request,open("pickle_data.txt","w"))
if __name__ == '__main__':
try:
ServerClass = BaseHTTPServer.HTTPServer
Protocol = "HTTP/1.0"
addr = len(sys.argv) < 2 and "0.0.0.0" or sys.argv[1]
port = len(sys.argv) < 3 and 80 or int(sys.argv[2])
HandlerClass.protocol_version = Protocol
httpd = ServerClass((addr, port), HandlerClass)
sa = httpd.socket.getsockname()
print "Serving HTTP on", sa[0], "port", sa[1], "..."
httpd.serve_forever()
except:
exit()

View File

@ -1,7 +1,5 @@
## Compose 简介
![Docker Compose 项目](_images/docker_compose.jpg)
`Compose` 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。从功能上看,跟 `OpenStack` 中的 `Heat` 十分类似。
其代码目前在 [https://github.com/docker/compose](https://github.com/docker/compose) 上开源。

View File

@ -1,6 +1,7 @@
## 使用
### 术语
首先介绍几个术语。
* 服务 (`service`):一个应用容器,实际上可以运行多个相同镜像的实例。
@ -10,197 +11,64 @@
可见,一个项目可以由多个服务(容器)关联而成,`Compose` 面向项目进行管理。
### 场景
下面,我们创建一个经典的 Web 项目:一个 [Haproxy](http://www.haproxy.org/),挂载三个 Web 容器。
创建一个 `compose-haproxy-web` 目录,作为项目工作目录,并在其中分别创建两个子目录:`haproxy` 和 `web`
最常见的项目是 web 网站,该项目应该包含 web 应用和缓存
### web 子目录
下面我们用 `Python` 来建立一个能够记录页面访问次数的 web 网站。
这里用 Python 程序来提供一个简单的 HTTP 服务,打印出访问者的 IP 和 实际的本地 IP。
#### web 应用
#### index.py
新建文件夹,在该目录中编写 `app.py` 文件
编写一个 `index.py` 作为服务器文件,代码为
```python
#!/usr/bin/python
#authors: yeasy.github.com
#date: 2013-07-05
from flask import Flask
from redis import Redis
import sys
import BaseHTTPServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
import socket
import fcntl
import struct
import pickle
from datetime import datetime
from collections import OrderedDict
app = Flask(__name__)
redis = Redis(host='redis', port=6379)
class HandlerClass(SimpleHTTPRequestHandler):
def get_ip_address(self,ifname):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
return socket.inet_ntoa(fcntl.ioctl(
s.fileno(),
0x8915, # SIOCGIFADDR
struct.pack('256s', ifname[:15])
)[20:24])
def log_message(self, format, *args):
if len(args) < 3 or "200" not in args[1]:
return
try:
request = pickle.load(open("pickle_data.txt","r"))
except:
request=OrderedDict()
time_now = datetime.now()
ts = time_now.strftime('%Y-%m-%d %H:%M:%S')
server = self.get_ip_address('eth0')
host=self.address_string()
addr_pair = (host,server)
if addr_pair not in request:
request[addr_pair]=[1,ts]
else:
num = request[addr_pair][0]+1
del request[addr_pair]
request[addr_pair]=[num,ts]
file=open("index.html", "w")
file.write("<!DOCTYPE html> <html> <body><center><h1><font color=\"blue\" face=\"Georgia, Arial\" size=8><em>HA</em></font> Webpage Visit Results</h1></center>")
for pair in request:
if pair[0] == host:
guest = "LOCAL: "+pair[0]
else:
guest = pair[0]
if (time_now-datetime.strptime(request[pair][1],'%Y-%m-%d %H:%M:%S')).seconds < 3:
file.write("<p style=\"font-size:150%\" >#"+ str(request[pair][1]) +": <font color=\"red\">"+str(request[pair][0])+ "</font> requests " + "from &lt<font color=\"blue\">"+guest+"</font>&gt to WebServer &lt<font color=\"blue\">"+pair[1]+"</font>&gt</p>")
else:
file.write("<p style=\"font-size:150%\" >#"+ str(request[pair][1]) +": <font color=\"maroon\">"+str(request[pair][0])+ "</font> requests " + "from &lt<font color=\"navy\">"+guest+"</font>&gt to WebServer &lt<font color=\"navy\">"+pair[1]+"</font>&gt</p>")
file.write("</body> </html>")
file.close()
pickle.dump(request,open("pickle_data.txt","w"))
@app.route('/')
def hello():
count = redis.incr('hits')
return 'Hello World! 该页面已被访问 {} 次。\n'.format(count)
if __name__ == '__main__':
try:
ServerClass = BaseHTTPServer.HTTPServer
Protocol = "HTTP/1.0"
addr = len(sys.argv) < 2 and "0.0.0.0" or sys.argv[1]
port = len(sys.argv) < 3 and 80 or int(sys.argv[2])
HandlerClass.protocol_version = Protocol
httpd = ServerClass((addr, port), HandlerClass)
sa = httpd.socket.getsockname()
print "Serving HTTP on", sa[0], "port", sa[1], "..."
httpd.serve_forever()
except:
exit()
```
#### index.html
生成一个临时的 `index.html` 文件,其内容会被 `index.py` 更新。
```bash
$ touch index.html
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
```
#### Dockerfile
编写 `Dockerfile` 文件,内容为
```docker
FROM python:2.7
WORKDIR /code
FROM python:3.6-alpine
ADD . /code
EXPOSE 80
CMD python index.py
WORKDIR /code
RUN pip install redis flask
CMD ["python", "app.py"]
```
### haproxy 目录
编写 `haproxy.cfg` 文件,内容为
```bash
global
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
#### docker-compose.yml
defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
listen stats
bind 0.0.0.0:70
stats enable
stats uri /
frontend balancer
bind 0.0.0.0:80
mode http
default_backend web_backends
backend web_backends
mode http
option forwardfor
balance roundrobin
server weba weba:80 check
server webb webb:80 check
server webc webc:80 check
option httpchk GET /
http-check expect status 200
```
### docker-compose.yml
编写 `docker-compose.yml` 文件,这个是 `Compose` 使用的主模板文件。内容十分简单,指定 3 个 `web` 容器,以及 1 个 `haproxy` 容器。
编写 `docker-compose.yml` 文件,这个是 Compose 使用的主模板文件。
```yaml
version: "3"
version: '3'
services:
weba:
build: ./web
expose:
- 80
webb:
build: ./web
expose:
- 80
webc:
build: ./web
expose:
- 80
haproxy:
image: haproxy:latest
volumes:
- ./haproxy:/haproxy-override
- ./haproxy/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
web:
build: .
ports:
- "80:80"
- "70:70"
expose:
- "80"
- "70"
- "5000:5000"
redis:
image: "redis:alpine"
```
### 运行 compose 项目
现在 `compose-haproxy-web` 目录结构如下:
```bash
compose-haproxy-web
├── docker-compose.yml
├── haproxy
│ └── haproxy.cfg
└── web
├── Dockerfile
├── index.html
└── index.py
```
在该目录下执行 `docker-compose up` 命令,会整合输出所有容器的输出。
#### 运行 compose 项目
```bash
$ docker-compose up
Recreating composehaproxyweb_webb_1...
Recreating composehaproxyweb_webc_1...
Recreating composehaproxyweb_weba_1...
Recreating composehaproxyweb_haproxy_1...
Attaching to composehaproxyweb_webb_1, composehaproxyweb_webc_1, composehaproxyweb_weba_1, composehaproxyweb_haproxy_1
```
此时访问本地的 `80` 端口,会经过 `haproxy` 自动转发到后端的某个 web 容器上,刷新页面,可以观察到访问的容器地址的变化。
访问本地 `70` 端口,可以查看到 `haproxy` 的统计信息。
此时访问本地 `5000` 端口,每次刷新页面,计数就会加 1。

View File

@ -2,7 +2,6 @@ version: "3"
services:
server:
# build: ./.travis
image: yeasy/docker_practice:latest
ports:
- 4000:4000
@ -27,7 +26,7 @@ services:
development:
build: ./.travis
image: yeasy/docker_practice:development
image: yeasy/docker_practice:latest
ports:
- 4000:4000
volumes:

View File

@ -98,6 +98,8 @@ $ sudo groupadd docker
$ sudo usermod -aG docker $USER
```
退出当前终端并重新登录,进行如下测试。
### 测试 Docker 是否安装正确
```bash

View File

@ -144,6 +144,8 @@ $ sudo groupadd docker
$ sudo usermod -aG docker $USER
```
退出当前终端并重新登录,进行如下测试。
### 测试 Docker 是否安装正确
```bash

View File

@ -102,6 +102,8 @@ $ sudo groupadd docker
$ sudo usermod -aG docker $USER
```
退出当前终端并重新登录,进行如下测试。
### 测试 Docker 是否安装正确
```bash

View File

@ -132,6 +132,8 @@ $ sudo groupadd docker
$ sudo usermod -aG docker $USER
```
退出当前终端并重新登录,进行如下测试。
### 测试 Docker 是否安装正确
```bash

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

View File

@ -33,7 +33,7 @@ nameserver 114.114.114.114
nameserver 8.8.8.8
```
如果用户想要手动指定容器的配置,可以利用下面的选项。
如果用户想要手动指定容器的配置,可以在使用 `docker run` 命令启动容器时加入如下参数:
`-h HOSTNAME` 或者 `--hostname=HOSTNAME` 设定容器的主机名,它会被写到容器内的 `/etc/hostname``/etc/hosts`。但它在容器外部看不到,既不会在 `docker ps` 中显示,也不会在其他的容器的 `/etc/hosts` 看到。
@ -41,4 +41,4 @@ nameserver 8.8.8.8
`--dns-search=DOMAIN` 设定容器的搜索域,当设定搜索域为 `.example.com` 时,在搜索一个名为 host 的主机时DNS 不仅搜索 host还会搜索 `host.example.com`
*注意:* 如果没有上述最后 2 个选项Docker 会默认用主机上的 `/etc/resolv.conf` 来配置容器。
>注意:如果在容器启动时没有指定最后两个参数Docker 会默认用主机上的 `/etc/resolv.conf` 来配置容器。