Docker搭建全棧式應(yīng)用示例(一)基礎(chǔ)篇

用docker搭建全棧式應(yīng)用

簡(jiǎn)介

本文將以docker為基礎(chǔ),搭建一套簡(jiǎn)單的應(yīng)用案例医吊。本文將假定讀者已經(jīng)有一定的Docker應(yīng)用基礎(chǔ)钱慢,如懂得用docker pull下載image,懂得用docker run運(yùn)行一個(gè)container等卿堂。該案例的應(yīng)用架構(gòu)將采用redis的master-slave模式作為數(shù)據(jù)存儲(chǔ)束莫,以django為框架提供web訪問,以haproxy作為負(fù)載均衡草描。其架構(gòu)圖如下.

應(yīng)用架構(gòu)圖

其中App1和App2屬于同一個(gè)Django的APP.

準(zhǔn)備工作

獲取相應(yīng)的docker images

  • 可以直接從docker官方獲取images
$ docker pull django
$ docker pull redis
$ docker pull haproxy
  • 獲取成功之后览绿,檢查一下images是否真的ok
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
haproxy             latest              46bc5babcc18        3 days ago          139.1 MB
redis               latest              84dbf5edc313        4 days ago          184.8 MB
django              latest              3b0bc67346a2        9 days ago          433.5 MB
  • 檢查一下各自的版本(root權(quán)限)
    redis版本
# docker run -it redis /bin/bash
root@a3ca293915cb:/data# redis-server -v
Redis server v=3.2.0 sha=00000000:0 malloc=jemalloc-4.0.3 bits=64 build=5382f69a4e75566b

haproxy版本

# docker run -it haproxy /bin/bash
root@b11f07766c49:/# haproxy -v
HA-Proxy version 1.6.5 2016/05/10
Copyright 2000-2016 Willy Tarreau <willy@haproxy.org>

django版本

# docker run -it django /bin/bash
root@1daf8d846018:/# django-admin version
1.9.6

檢查完后,可以用docker rm把不用的containers刪掉

# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS               NAMES
1daf8d846018        django              "/bin/bash"              2 minutes ago       Exited (0) 6 seconds ago                       sleepy_hypatia
b11f07766c49        haproxy             "/docker-entrypoint.s"   3 minutes ago       Exited (0) 2 minutes ago                       elegant_tesla
a3ca293915cb        redis               "docker-entrypoint.sh"   5 minutes ago       Exited (0) 3 minutes ago                       stupefied_cray
# docker rm `docker ps -a | grep 'Exited' | awk '{print $1}'`
1daf8d846018
b11f07766c49
a3ca293915cb

從上穗慕,本文各版本采用如下:

service version
haproxy 1.6.5
django 1.9.6
redis 3.2.0

啟動(dòng)containers

本案例中containers的有關(guān)啟動(dòng)配置如下:

container image service ports volumes links
redis-master redis redis-server - master:/data -
redis-slave1 redis redis-server - slave1:/data redis-master:master
redis-slave2 redis redis-server - slave2:/data redis-master:master
app1 django django app - app:/data redis-master:redis
app2 django django app - app:/data redis-master:redis
haproxy haproxy haproxy 6301:6301 haproxy:/data app1:app1 app2:app2

啟動(dòng)redis

  • 啟動(dòng)redis-master
    在本地當(dāng)前目錄下創(chuàng)建子目錄master饿敲,并將master掛載到container里的/data目錄。container名字為redis-master逛绵。為了方便調(diào)試诀蓉,這里同時(shí)啟動(dòng)交互式模式-it,并同時(shí)打開bash

    # mkdir master
    # docker run -it --name redis-master -v `pwd`/master:/data redis /bin/bash
    root@3d187b223f56:/data#
    

    添加一個(gè)測(cè)試條目暑脆,取key為redis_app渠啤,該測(cè)試條目將被app1跟app2查詢:

    root@3d187b223f56:/data# redis-cli
    127.0.0.1:6379> set redis_app "Hello redis app!"
    OK
    127.0.0.1:6379> get redis_app
    "Hello redis app!"
    
  • 啟動(dòng)redis-slave1
    本文案例中將采用兩個(gè)redis的slave,這里首先啟動(dòng)第一個(gè)添吗。container名字為redis-slave1沥曹,同時(shí)為了方便的連接到redis master,這里直接用--linkredis-mastercontainer連接同時(shí)命名為master。其實(shí)際效果相當(dāng)于往/etc/hosts添加一條記錄妓美,映射master的域名到redis-master的IP僵腺。通過這種方式,就不需要手工的添加master的IP壶栋,docker在啟動(dòng)的時(shí)候會(huì)自動(dòng)添加辰如。

    # docker run -it --name redis-slave1 --link redis-master:master -v `pwd`/slave1:/data redis /bin/bash
    root@cef73ae816be:/data# cat /etc/hosts
    172.17.0.3      cef73ae816be
    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      master 3d187b223f56 redis-master
    

    可以看出,--link實(shí)際上在/etc/hosts下添加了一條新的映射贵试,分別把redis-master的別名master琉兜、container ID以及container name映射到master的IP。

    172.17.0.2      master 3d187b223f56 redis-master
    

    如果沒有錯(cuò)誤毙玻,那么上面在master中設(shè)置的條目應(yīng)該可以查詢到:

    root@cef73ae816be:/data# redis-cli
    127.0.0.1:6379> get redis_app
    "Hello redis app!"
    
  • 啟動(dòng)redis-slave2
    與redis-slave1同樣的方式啟動(dòng)redis-slave2

    # docker run -it --name redis-slave2 --link redis-master:master -v `pwd`/slave2:/data redis /bin/bash
    root@1f22e9e15e8b:/data# cat /etc/hosts
    172.17.0.4      1f22e9e15e8b
    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      master 3d187b223f56 redis-master
    

    如果沒有錯(cuò)誤豌蟋,那么上面在master中設(shè)置的條目應(yīng)該可以查詢到:

    root@cef73ae816be:/data# redis-cli
    127.0.0.1:6379> get redis_app
    "Hello redis app!"
    
  • 啟動(dòng)app1
    app1需要連接到redis服務(wù),因此需要把redis-mastercontainer連起來桑滩。同時(shí)為其創(chuàng)建app目錄梧疲,由于app1跟app2共享同一個(gè)Django項(xiàng)目,這里就不再單獨(dú)為他們創(chuàng)建各自的目錄运准。

    # mkdir app
    # docker run -it --name app1 --link redis-master:redis -v `pwd`/app/:/data django /bin/bash
    root@7e6e49321993:/#
    

配置

配置redis

  • 獲取redis初始配置

    本文采用的版本為3.2.0, 可通過如下方式獲取

    # wget https://raw.githubusercontent.com/antirez/redis/3.2.0/redis.conf
    
  • 配置redis-master

    拷貝redis.confmaster目錄.

    # cp redis.conf master/
    

    編輯改配置文件幌氮。默認(rèn)里面有非常多的配置選項(xiàng),這里只需要關(guān)注幾個(gè)胁澳,并改成如下:

    bind 0.0.0.0
    protected-mode yes
    daemonize yes
    logfile /var/log/redis.log
    

    由于已經(jīng)將./master掛載到container的/data目錄浩销,因此本地的改動(dòng)在container里面也是可見的。

  • 配置redis-slave1

    拷貝redis.confslave1目錄.

    # cp redis.conf slave1/
    

    編輯改配置文件听哭。默認(rèn)里面有非常多的配置選項(xiàng)慢洋,這里只需要關(guān)注幾個(gè),并改成如下:

    bind 0.0.0.0
    protected-mode yes
    daemonize yes
    logfile /var/log/redis.log
    slaveof master 6379
    

    最后一項(xiàng)slaveof將slave1設(shè)置為master的slave陆盘。同樣普筹,由于已經(jīng)將./slave1掛載到container的/data目錄,因此本地的改動(dòng)在container里面也是可見的隘马。

  • 配置redis-slave2

    配置方式與redis-slave1一致太防,因此,直接拷貝slave1/redis.confslave2目錄.

    # cp slave1/redis.conf slave2/
    

配置Django App

  • 配置app1

    首先需要?jiǎng)?chuàng)建Django項(xiàng)目,這需要登錄到app1系統(tǒng)中才能夠調(diào)用Django命令來創(chuàng)建酸员。

    # docker attach app1
    root@7e6e49321993:/# cd /data
    root@7e6e49321993:/# django-admin startproject redisapp
    root@4b8240acb25a:/data# ls
    redisapp
    root@4b8240acb25a:/data# cd redisapp/
    root@4b8240acb25a:/data/redisapp# ls
    manage.py  redisapp
    

    接下來需要編輯Django代碼以支持本案例中一個(gè)簡(jiǎn)單的API:/query/蜒车,此API將獲取redis中的key為redis_app的值(請(qǐng)注意,該值在上面啟動(dòng)redis的時(shí)候已經(jīng)設(shè)置好了)幔嗦,并將結(jié)果返回給瀏覽器酿愧。由于container中大量的linux工具都沒有,因此需要到主機(jī)上去編輯邀泉。app1container將app目錄掛載進(jìn)去了嬉挡,因此在container中的創(chuàng)建的Django項(xiàng)目實(shí)際上在app目錄下也是可見的钝鸽。

    • 安卓redis client

      由于django app需要訪問redis數(shù)據(jù)庫(kù),因此需要先安裝redis client

      root@7e6e49321993:/data/redisapp# pip install redis
      Collecting redis
        Downloading redis-2.10.5-py2.py3-none-any.whl (60kB)
            100% |████████████████████████████████| 61kB 123kB/s
            Installing collected packages: redis
            Successfully installed redis-2.10.5
      
    • 編輯views.py文件

      # vim app/redisapp/redisapp/views.py
      

      初始狀態(tài)庞钢,views.py文件并不存在拔恰,添加并編輯,內(nèi)容如下:

      from django.http import HttpResponse
      import socket
      import redis
      
      
      def query(request):
          r = redis.StrictRedis(host='redis', port=6379, db=0)
          value = r.get('redis_app')
          return HttpResponse('hello world from ' + socket.gethostname() + ', with value: ' + str(value))
      
    • 編輯urls.py文件

      # vim app/redisapp/redisapp/views.py
      

      編輯內(nèi)容如下基括,只要是添加views.py中定義的view函數(shù)跟url的對(duì)應(yīng):

      from django.conf.urls import url
      from django.contrib import admin
      
      from redisapp.views import *
      
      urlpatterns = [
          url(r'^admin/', admin.site.urls),
              url(r'^query/', query),
              ]
      
    • 編輯settings.py文件

      # vim app/redisapp/redisapp/settings.py
      

      主要是講默認(rèn)生成的redisapp添加到INSTALLED_APPS中颜懊,添加完后應(yīng)該如下:

      INSTALLED_APPS = [
          'django.contrib.admin',
          'django.contrib.auth',
          'django.contrib.contenttypes',
          'django.contrib.sessions',
          'django.contrib.messages',
          'django.contrib.staticfiles',
          'redisapp'
      ]
      
    • 初始化數(shù)據(jù)庫(kù)

      在啟動(dòng)django程序之前,必須初始化數(shù)據(jù)庫(kù)风皿。默認(rèn)情況下河爹,采用的sqlite數(shù)據(jù)庫(kù)。

      root@2298dd360bbd:/data/redisapp# python manage.py migrate
      Operations to perform:
        Apply all migrations: admin, contenttypes, sessions, auth
      Running migrations:
        Rendering model states... DONE
        Applying contenttypes.0001_initial... OK
        Applying auth.0001_initial... OK
        Applying admin.0001_initial... OK
        Applying admin.0002_logentry_remove_auto_add... OK
        Applying contenttypes.0002_remove_content_type_name... OK
        Applying auth.0002_alter_permission_name_max_length... OK
        Applying auth.0003_alter_user_email_max_length... OK
        Applying auth.0004_alter_user_username_opts... OK
        Applying auth.0005_alter_user_last_login_null... OK
        Applying auth.0006_require_contenttypes_0002... OK
        Applying auth.0007_alter_validators_add_error_messages... OK
        Applying sessions.0001_initial... OK
      

    至此揪阶,app1已經(jīng)全部配置并初始化完畢。

  • 配置app2

    app2與app1共享同一個(gè)Django項(xiàng)目患朱,因此不需要為app2做任何特別的配置鲁僚。

  • 配置haproxy

    haproxy依賴于它的配置文件,在配置文件中必須把a(bǔ)pp1跟app2都加進(jìn)去裁厅,這樣haproxy就可以為他們做load balance了冰沙。

    # vim haproxy/haproxy.cfg
    

    編輯內(nèi)容如下:

    global
      maxconn 50000
      daemon
      pidfile /var/run/haproxy.pid
      log   127.0.0.1       local0
      nbproc 4
      #debug
    
    defaults
      mode http
      balance roundrobin
      maxconn 25000
      option httplog
      option abortonclose
      option httpclose
      option forwardfor
      option redispatch
      option redispatch
    
      retries 3
    
      timeout client  30s
      timeout connect 30s
      timeout server  30s
    
    
    listen redis_proxy
      bind :6301
      mode http
      stats enable
      stats uri /stats
      log   127.0.0.1       local0 debug
      server app1 app1:8001 check inter 2000 rise 2 fall 5
      server app2 app2:8002 check inter 2000 rise 2 fall 5
    

    如果需要調(diào)試,可以吧global中的debug打開执虹。特別注意的是關(guān)于app1跟app2的配置拓挥,必須跟他們啟動(dòng)的端口保持一致。因?yàn)樵谇懊嬉呀?jīng)通過--linkapp以及app2連接進(jìn)來袋励,因此在寫address:port時(shí)候可以直接使用app1跟app2侥啤。

啟動(dòng)services

啟動(dòng)redis service

  • 啟動(dòng)redis-master service

    • attach redis-master container

      # docker start redis-master
      redis-master
      # docker attach redis-master
      root@3d187b223f56:/data#
      
    • 啟動(dòng)service

      root@3d187b223f56:/data# redis-server redis.conf
      root@3d187b223f56:/data# redis-cli
      127.0.0.1:6379> get redis_app
      "Hello redis app!"
      
  • 啟動(dòng)redis-slave1 service

    • attach redis-slave1 container

      # docker start redis-slave1
      redis-slave1
      root@neil-centos1:hademo# docker attach redis-slave1
      root@cef73ae816be:/data# redis-cli
      
    • 啟動(dòng)service

      root@cef73ae816be:/data# redis-server redis.conf
      root@cef73ae816be:/data# redis-cli
      127.0.0.1:6379> get redis_app
      "Hello redis app!"
      
  • 啟動(dòng)redis-slave2 service

    與啟動(dòng)redis-slave1 service一樣,這里不再贅述茬故。

啟動(dòng)app service

  • 啟動(dòng)app1 service

    • attach app1 container

      # docker start app1
      app1
      root@neil-centos1:hademo# docker attach app1
      root@7e6e49321993:/#
      
    • 啟動(dòng)service

      root@7e6e49321993:/data# cd redisapp/
      root@7e6e49321993:/data# python manage.py runserver 0.0.0.0:8001
      Performing system checks...
      
      System check identified no issues (0 silenced).
      
      
      May 16, 2016 - 12:51:39
      Django version 1.9.6, using settings 'redisapp.settings'
      Starting development server at http://0.0.0.0:8001/
      Quit the server with CONTROL-C.
      
      
  • 啟動(dòng)app2 service

    • attach app2 container

       docker start app2
       app2
       # docker attach app2
       root@13d9f084c18b:/#
      
    • 啟動(dòng)service

      root@13d9f084c18b:/data# cd redisapp/
      root@13d9f084c18b:/data/redisapp# python manage.py runserver 0.0.0.0:8002
      Performing system checks...
      
      System check identified no issues (0 silenced).
      May 16, 2016 - 12:56:08
      Django version 1.9.6, using settings 'redisapp.settings'
      Starting development server at http://0.0.0.0:8002/
      Quit the server with CONTROL-C.
      
      

啟動(dòng)haproxy service

  • attach haproxy container

    # docker start haproxy
    haproxy
    # docker attach haproxy
    root@7e0f805cd85c:/#
    
  • 啟動(dòng)service

    root@7e0f805cd85c:/data# haproxy -f haproxy.cfg
    [WARNING] 136/130034 (6) : Proxy 'redis_proxy': in multi-process mode, stats will be limited to process assigned to the current request.
    root@7e0f805cd85c:/data#
    

至此盖灸,所有的service已經(jīng)成功啟動(dòng)』前牛可以通過uri http://<host ip>:6031/query/訪問本案例中web service赁炎。還可以通過http://<host ip>:6031/stats來查詢haproxy的統(tǒng)計(jì)信息。

結(jié)語

本文中所涉及的配置以及代碼可以在這個(gè)github repo找到: https://github.com/keysaim/demos/tree/master/docker-redis-django钾腺。此外徙垫,還可以訪問博主的個(gè)人博客:https://keysaim.github.io

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末放棒,一起剝皮案震驚了整個(gè)濱河市姻报,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌间螟,老刑警劉巖逗抑,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剧辐,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡邮府,警方通過查閱死者的電腦和手機(jī)荧关,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來褂傀,“玉大人忍啤,你說我怎么就攤上這事∠杀伲” “怎么了同波?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)叠国。 經(jīng)常有香客問我未檩,道長(zhǎng),這世上最難降的妖魔是什么粟焊? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任冤狡,我火速辦了婚禮,結(jié)果婚禮上项棠,老公的妹妹穿的比我還像新娘悲雳。我一直安慰自己,他們只是感情好香追,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布合瓢。 她就那樣靜靜地躺著,像睡著了一般透典。 火紅的嫁衣襯著肌膚如雪晴楔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天峭咒,我揣著相機(jī)與錄音滥崩,去河邊找鬼。 笑死讹语,一個(gè)胖子當(dāng)著我的面吹牛钙皮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播顽决,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼短条,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了才菠?” 一聲冷哼從身側(cè)響起茸时,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎赋访,沒想到半個(gè)月后可都,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缓待,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年渠牲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了娄猫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喉镰。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡巾钉,死狀恐怖沽一,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情答姥,我是刑警寧澤铣除,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站鹦付,受9級(jí)特大地震影響尚粘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜敲长,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一郎嫁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧潘明,春花似錦行剂、人聲如沸秕噪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽腌巾。三九已至遂填,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間澈蝙,已是汗流浹背吓坚。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留灯荧,地道東北人礁击。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像逗载,于是被迫代替她去往敵國(guó)和親哆窿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容