mirror of
				https://github.com/yeasy/docker_practice.git
				synced 2025-10-31 10:11:34 +00:00 
			
		
		
		
	Add compose quick start example
This commit is contained in:
		
							
								
								
									
										200
									
								
								compose/usage.md
									
									
									
									
									
								
							
							
						
						
									
										200
									
								
								compose/usage.md
									
									
									
									
									
								
							| @@ -5,3 +5,203 @@ | ||||
|  | ||||
| * 服务(service):一个应用容器,实际上可以运行多个相同镜像的实例。 | ||||
| * 项目(project):由一组关联的应用容器组成的一个完整业务单元。 | ||||
|  | ||||
| 可见,一个项目可以由多个服务(容器)关联而成,Compose 面向项目进行管理。 | ||||
|  | ||||
| ### 场景 | ||||
| 下面,我们创建一个经典的 Web 项目:一个 [Haproxy](www.haproxy.org),挂载三个 Web 容器。 | ||||
|  | ||||
| 创建一个 `compose-haproxy-web` 目录,作为项目工作目录,并在其中分别创建两个子目录:`haproxy` 和 `web`。 | ||||
|  | ||||
| ### Web 子目录 | ||||
|  | ||||
| 这里用 Python 程序来提供一个简单的 HTTP 服务,打印出访问者的 IP 和 实际的本地 IP。 | ||||
|  | ||||
| #### index.py | ||||
|  | ||||
| 编写一个 `index.py` 作为服务器文件,代码为 | ||||
| ```sh | ||||
| #!/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() | ||||
| ``` | ||||
|  | ||||
| #### index.html | ||||
| 生成一个临时的 `index.html` 文件,其内容会被 index.py 更新。 | ||||
| ```sh | ||||
| $ touch index.html | ||||
| ``` | ||||
|  | ||||
| #### Dockerfile | ||||
| 生成一个 Dockerfile,内容为 | ||||
| ```sh | ||||
| FROM python:2.7 | ||||
| WORKDIR /code | ||||
| ADD . /code | ||||
| EXPOSE 80 | ||||
| CMD python index.py | ||||
| ``` | ||||
|  | ||||
| ### haproxy 目录 | ||||
| 在其中生成一个 `haproxy.cfg` 文件,内容为 | ||||
| ```sh | ||||
| 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 :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 容器。 | ||||
|  | ||||
| ```sh | ||||
| 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 | ||||
|     links: | ||||
|         - weba | ||||
|         - webb | ||||
|         - webc | ||||
|     ports: | ||||
|         - "80:80" | ||||
|         - "70:70" | ||||
|     expose: | ||||
|         - "80" | ||||
|         - "70" | ||||
| ``` | ||||
|  | ||||
| ### 运行 compose 项目 | ||||
| 现在 compose-haproxy-web 目录长成下面的样子。 | ||||
| ```sh | ||||
| compose-haproxy-web | ||||
| ├── docker-compose.yml | ||||
| ├── haproxy | ||||
| │   └── haproxy.cfg | ||||
| └── web | ||||
|     ├── Dockerfile | ||||
|     ├── index.html | ||||
|     └── index.py | ||||
| ``` | ||||
| 在该目录下执行 `docker-compose up` 命令,会整合输出所有容器的输出。 | ||||
| ``` | ||||
| $sudo 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 的统计信息。 | ||||
|  | ||||
| 当然,还可以使用 consul、etcd 等实现服务发现,这样就可以避免手动指定后端的 web 容器了,更为灵活。 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user