mirror of
https://github.com/yeasy/docker_practice.git
synced 2024-12-25 14:38:54 +00:00
Update compose #288
This commit is contained in:
parent
6bcce7e562
commit
8939af4f97
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
* 0.9-rc3: 2017-12-20
|
* 0.9-rc3: 2017-12-20
|
||||||
|
|
||||||
|
* 精简示例代码
|
||||||
|
|
||||||
* 调整目录结构
|
* 调整目录结构
|
||||||
|
|
||||||
* 0.9-rc2: 2017-12-10
|
* 0.9-rc2: 2017-12-10
|
||||||
|
5
compose/demo/app/Dockerfile
Normal file
5
compose/demo/app/Dockerfile
Normal 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
13
compose/demo/app/app.py
Normal 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)
|
10
compose/demo/app/docker-compose.yml
Normal file
10
compose/demo/app/docker-compose.yml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
version: '3'
|
||||||
|
services:
|
||||||
|
|
||||||
|
web:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "5000:5000"
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: "redis:alpine"
|
@ -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"
|
|
@ -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
|
|
@ -1,5 +0,0 @@
|
|||||||
FROM python:2.7
|
|
||||||
WORKDIR /code
|
|
||||||
ADD . /code
|
|
||||||
EXPOSE 80
|
|
||||||
CMD python index.py
|
|
@ -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 <<font color=\"blue\">"+guest+"</font>> to WebServer <<font color=\"blue\">"+pair[1]+"</font>></p>")
|
|
||||||
else:
|
|
||||||
file.write("<p style=\"font-size:150%\" >#"+ str(request[pair][1]) +": <font color=\"maroon\">"+str(request[pair][0])+ "</font> requests " + "from <<font color=\"navy\">"+guest+"</font>> to WebServer <<font color=\"navy\">"+pair[1]+"</font>></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()
|
|
198
compose/usage.md
198
compose/usage.md
@ -1,6 +1,7 @@
|
|||||||
## 使用
|
## 使用
|
||||||
|
|
||||||
### 术语
|
### 术语
|
||||||
|
|
||||||
首先介绍几个术语。
|
首先介绍几个术语。
|
||||||
|
|
||||||
* 服务 (`service`):一个应用容器,实际上可以运行多个相同镜像的实例。
|
* 服务 (`service`):一个应用容器,实际上可以运行多个相同镜像的实例。
|
||||||
@ -10,197 +11,64 @@
|
|||||||
可见,一个项目可以由多个服务(容器)关联而成,`Compose` 面向项目进行管理。
|
可见,一个项目可以由多个服务(容器)关联而成,`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
|
```python
|
||||||
#!/usr/bin/python
|
from flask import Flask
|
||||||
#authors: yeasy.github.com
|
from redis import Redis
|
||||||
#date: 2013-07-05
|
|
||||||
|
|
||||||
import sys
|
app = Flask(__name__)
|
||||||
import BaseHTTPServer
|
redis = Redis(host='redis', port=6379)
|
||||||
from SimpleHTTPServer import SimpleHTTPRequestHandler
|
|
||||||
import socket
|
|
||||||
import fcntl
|
|
||||||
import struct
|
|
||||||
import pickle
|
|
||||||
from datetime import datetime
|
|
||||||
from collections import OrderedDict
|
|
||||||
|
|
||||||
class HandlerClass(SimpleHTTPRequestHandler):
|
@app.route('/')
|
||||||
def get_ip_address(self,ifname):
|
def hello():
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
count = redis.incr('hits')
|
||||||
return socket.inet_ntoa(fcntl.ioctl(
|
return 'Hello World! 该页面已被访问 {} 次。\n'.format(count)
|
||||||
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 <<font color=\"blue\">"+guest+"</font>> to WebServer <<font color=\"blue\">"+pair[1]+"</font>></p>")
|
|
||||||
else:
|
|
||||||
file.write("<p style=\"font-size:150%\" >#"+ str(request[pair][1]) +": <font color=\"maroon\">"+str(request[pair][0])+ "</font> requests " + "from <<font color=\"navy\">"+guest+"</font>> to WebServer <<font color=\"navy\">"+pair[1]+"</font>></p>")
|
|
||||||
file.write("</body> </html>")
|
|
||||||
file.close()
|
|
||||||
pickle.dump(request,open("pickle_data.txt","w"))
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
try:
|
app.run(host="0.0.0.0", debug=True)
|
||||||
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
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Dockerfile
|
#### Dockerfile
|
||||||
|
|
||||||
编写 `Dockerfile` 文件,内容为
|
编写 `Dockerfile` 文件,内容为
|
||||||
|
|
||||||
```docker
|
```docker
|
||||||
FROM python:2.7
|
FROM python:3.6-alpine
|
||||||
WORKDIR /code
|
|
||||||
ADD . /code
|
ADD . /code
|
||||||
EXPOSE 80
|
WORKDIR /code
|
||||||
CMD python index.py
|
RUN pip install redis flask
|
||||||
|
CMD ["python", "app.py"]
|
||||||
```
|
```
|
||||||
|
|
||||||
### haproxy 目录
|
#### docker-compose.yml
|
||||||
编写 `haproxy.cfg` 文件,内容为
|
|
||||||
```bash
|
|
||||||
global
|
|
||||||
log 127.0.0.1 local0
|
|
||||||
log 127.0.0.1 local1 notice
|
|
||||||
|
|
||||||
defaults
|
编写 `docker-compose.yml` 文件,这个是 Compose 使用的主模板文件。
|
||||||
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` 容器。
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: "3"
|
version: '3'
|
||||||
services:
|
services:
|
||||||
|
|
||||||
weba:
|
web:
|
||||||
build: ./web
|
build: .
|
||||||
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:
|
ports:
|
||||||
- "80:80"
|
- "5000:5000"
|
||||||
- "70:70"
|
|
||||||
expose:
|
redis:
|
||||||
- "80"
|
image: "redis:alpine"
|
||||||
- "70"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 运行 compose 项目
|
#### 运行 compose 项目
|
||||||
现在 `compose-haproxy-web` 目录结构如下:
|
|
||||||
```bash
|
|
||||||
compose-haproxy-web
|
|
||||||
├── docker-compose.yml
|
|
||||||
├── haproxy
|
|
||||||
│ └── haproxy.cfg
|
|
||||||
└── web
|
|
||||||
├── Dockerfile
|
|
||||||
├── index.html
|
|
||||||
└── index.py
|
|
||||||
```
|
|
||||||
在该目录下执行 `docker-compose up` 命令,会整合输出所有容器的输出。
|
|
||||||
```bash
|
```bash
|
||||||
$ docker-compose up
|
$ 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 容器上,刷新页面,可以观察到访问的容器地址的变化。
|
此时访问本地 `5000` 端口,每次刷新页面,计数就会加 1。
|
||||||
|
|
||||||
访问本地 `70` 端口,可以查看到 `haproxy` 的统计信息。
|
|
||||||
|
Loading…
Reference in New Issue
Block a user