有需求須要對django系統進行docker化,以達到靈活部署和容災。該系統基於django 2.2版本開發,數據庫採用mongodb,服務器使用nginx,因系統有部分異步任務,異步任務則採用clelery+redis實現。
基於該需求,所採用的思路是:「基於ubuntu16.04」源鏡像,根據dockerfile製做各個運行環境的鏡像。因docker提倡單應用單鏡像,故這裏將django源代碼程序做爲一個鏡像、mongodb做爲一個鏡像、nginx做爲一個鏡像、redis做爲一個鏡像。並最終使用docker-compose對這些鏡像作編排。(假設當前已瞭解docker與docker-compose知識)html
下面就是一步步製做docker鏡像了。關於各個鏡像的Dockerfile模板,這裏有一個很是好用的網站,可在網站中搜索本身感興趣的項目,獲得其Dockerfile。假設ubuntu16.04的源鏡像及版本名爲:ubuntu:16.04。
首先咱們在宿主機(宿主機爲ubuntu16.04系統,用戶爲user)中創建一個父文件夾例如名爲vs,其中的目錄以下:
node
mongodb_vs: 存放mongod的數據、配置文件與dockerfile文件;
vsapp: 存放django系統的源代碼、相關配置文件與dockerfile文件;
redis_vs: 存放redis的配置文件與dockerfile文件;
nginx_vs: 存放nginx的配置文件與dockerfile文件。python
首先是mongodb鏡像的Dockerfile,內容以下:mysql
FROM ubuntu:16.04 RUN apt-get update RUN apt-get install gcc -y RUN apt-get install g++ -y RUN apt-get install make -y RUN apt-get install wget -y # Install MongoDB. RUN \ apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10 && \ echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' > /etc/apt/sources.list.d/mongodb.list && \ apt-get update && \ apt-get install -y mongodb-org && \ rm -rf /var/lib/apt/lists/* # Define mountable directories. VOLUME ["/data/db"] # Define working directory. WORKDIR /data RUN mkdir bin && mkdir log COPY mongodb.conf ./bin/ # Expose ports. # - 27017: process # - 28017: http EXPOSE 27017 EXPOSE 28017 # Define default command. # CMD ["mongod", "-f", "./bin/mongodb.conf"]
Dockerfile解釋:首先更新ubuntu的源,而後下載mongodb的安裝包並安裝;在鏡像中定義了「/data/db」的數據卷路徑,並在/data/路徑下建立了bin文件夾與log文件夾(db文件夾與log文件夾分別用來存儲mongodb的數據庫和mongodb運行的log。bin文件夾用來存放mongodb的配置文件);將宿主機下的mongodb配置文件「mongodb.conf」文件拷貝到鏡像中的bin文件夾下;暴露mongodb運行的相應端口。
Dockerfile運行條件:要想運行該Dockerfile,須要有配置文件mongodb.conf的支持。在mongodb_vs文件夾下放入Dockerfile並建立一個文件mongodb.conf和一個data文件夾,data文件夾中有db和log兩個空文件夾(db和log用來存儲mongodb運行中的數據庫和log)。總體目錄以下:nginx
--mongodb_vs --Dockerfile --mongodb.conf --data --db --log
mongodb.conf內容以下:git
# db path dbpath = /data/db/ # log path logpath = /data/log/logs.log port = 27017 # fork = true # auth = true
以上內容中,fork表示是否在後臺運行mongodb,auth表示mongodb是否要進行認證,目前咱們先將這兩個禁用掉。
編譯鏡像:在mongodb_vs文件夾下運行以下命令:github
docker build -t mongodb:v1.0 .
命令運行後如果沒有報錯,則會編譯出一個名爲:mongodb:v1.0的鏡像。
運行容器:在mongodb文件夾下運行以下命令:web
docker run -it --name mongodb_test -p 27017:27017 -p 27018:27018 -v /home/user/vs/mongodb_vs/data/db:/data/db -v /home/user/vs/mongodb_vs/data/log:/data/log mongodb:v1.0
咱們基於mongodb_vs鏡像在前臺運行了一個名爲mongodb_test的容器,並將其端口與宿主機端口綁定,將mongodb產生的數據、log與宿主機進行映射。
若無報錯,則會進入到該容器中,在容器中運行命令:mongod -f ./bin/mongodb.conf --fork則會在後臺啓動開mongodb服務。咱們能夠在該容器中再輸入mongo命令,若能正常進入到mongodb的shell中,則說明mongodb啓動成功(也可用工具檢驗是否能鏈接到該mongodb實例)。redis
因該系統採用python的django框架完成。故須要系統有python環境。咱們能夠先基於ubuntu源鏡像製做一個python3的鏡像,再基於python3的鏡像製做源程序鏡像。
製做python3的鏡像方法有不少,這裏列出一種供參考:
python3.6.3的Dockerfilesql
FROM ubuntu:16.04 RUN apt-get update RUN apt-get -y install gcc make zlib1g zlib1g-dev openssl libpcre3 libpcre3-dev RUN apt-get -y install libbz2-dev libsqlite3-dev libxml2-dev libffi-dev libssl-dev libxslt1-dev RUN apt-get -y install wget RUN apt-get -y upgrade RUN apt-get -y dist-upgrade RUN apt-get -y install bzip2 RUN apt-get -y install python3-pip python3-dev RUN wget https://www.python.org/ftp/python/3.6.3/Python-3.6.3.tar.xz RUN tar -xvf Python-3.6.3.tar.xz RUN cd Python-3.6.3 && ./configure && make -j 8 && make install
運行構建命令:docker build -t python:v3.6.3 .便可製做出python3.6.3的鏡像。
下面就是製做源程序的鏡像,製做以前還須要一些準備工做:
將源程序代碼放入到vsapp文件夾下,例如源代碼項目名爲:vscode(vscode子一級目錄下有manage.py文件);爲了使項目支持nginx,在vscode子一級目錄下放入名爲uwsgi_params文件,文件內容爲:
uwsgi_param QUERY_STRING $query_string; uwsgi_param REQUEST_METHOD $request_method; uwsgi_param CONTENT_TYPE $content_type; uwsgi_param CONTENT_LENGTH $content_length; uwsgi_param REQUEST_URI $request_uri; uwsgi_param PATH_INFO $document_uri; uwsgi_param DOCUMENT_ROOT $document_root; uwsgi_param SERVER_PROTOCOL $server_protocol; uwsgi_param REQUEST_SCHEME $scheme; uwsgi_param HTTPS $https if_not_empty; uwsgi_param REMOTE_ADDR $remote_addr; uwsgi_param REMOTE_PORT $remote_port; uwsgi_param SERVER_PORT $server_port; uwsgi_param SERVER_NAME $server_name;
利用命令「pip freeze > requirements.txt」將源程序所須要的python依賴包都導出到requirements.txt文件中。並將該文件放入到vsapp文件夾下。我這裏的requirements.txt內容以下,供參考:
beautifulsoup4==4.6.0 redis==2.10.6 celery==3.1.26.post2 celery-with-redis==3.0 Django==2.2.2 django-rest-framework-mongoengine==3.3.1 jira==2.0.0 ldap3==2.6 mongoengine==0.17.0 multi-key-dict==2.0.3 mysqlclient==1.3.13 pymongo==3.8.0 python-jenkins==1.4.0 requests==2.22.0 requests-oauthlib==1.2.0 requests-toolbelt==0.9.1 sqlparse==0.3.0 urllib3==1.25.3 xlrd==1.2.0 xlwt==1.3.0 generic==0.3.1 uWSGI==2.0.17.1 djangorestframework==3.9.4
因項目中使用了celery,故還要將celery的配置文件放入到vsapp中。在vsapp中創建名爲celeryconf的文件夾,下載官方的兩個腳本並放入到celeryconf中;在vsapp中創建名爲celeryd的文件,並將如下內容存儲到該文件中:
# Names of nodes to start # most will only start one node: CELERYD_NODES="worker1" # but you can also start multiple and configure settings # for each in CELERYD_OPTS (see `celery multi --help` for examples). #CELERYD_NODES="worker1 worker2 worker3" # Absolute or relative path to the 'celery' command: CELERY_BIN="/usr/local/bin/celery" #CELERY_BIN="/virtualenvs/def/bin/celery" # App instance to use # comment out this line if you don't use an app # 這裏填寫實際的項目中項目名 CELERY_APP="vscode" # or fully qualified: #CELERY_APP="proj.tasks:app" # Where to chdir at start. # 這裏填寫項目中應用名在容器中對應的絕對路徑,因編譯鏡像時我這裏命名爲/web/vscode/ CELERYD_CHDIR="/web/vscode/" # Extra command-line arguments to the worker CELERYD_OPTS="--time-limit=300 --concurrency=8" # %N will be replaced with the first part of the nodename. CELERYD_LOG_FILE="/var/log/celery/worker1.log" CELERYD_PID_FILE="/var/run/celery/%N.pid" # Workers should run as an unprivileged user. # You need to create this user manually (or you can choose # a user/group combination that already exists, e.g. nobody). CELERYD_USER="root" CELERYD_GROUP="root" # If enabled pid and log directories will be created if missing, # and owned by the userid/group configured. CELERY_CREATE_DIRS=1
如果想查看celery運行的log,能夠在vsapp下創建一個名爲celerywork.log的文件。
關於celery的配置詳情,可參考這篇博客
因源程序中採用的是「nginx + uwsgi」搭建服務器端,故這裏須要對uwsgi進行配置。在vsapp下創建名爲vsapp_uwsgi.ini的文件。並在其中保存如下內容:
# mysite_uwsgi.ini file [uwsgi] # Django-related settings # the base directory (full path) chdir = /web/vscode # Django's wsgi file module = vscode.wsgi # the virtualenv (full path) # home = /var/local/bin/python3 # process-related settings # master master = true # maximum number of worker processes processes = 4 chmod-socket = 666 # 這裏指定了與nginx對接的端口爲8000 socket = :8000 # clear environment on exit vacuum = true uid = www-data gid = www-data pidfile = /web/webapp_uwsgi.pid # daemonize = /web/uwsgi_log.log
下面就是配置源程序運行的啓動命令。因源程序運行既須要啓動uwsgi還須要啓動celery的異步任務與定時任務。故咱們在vsapp下創建名爲run_web.sh的文件,並放入以下內容:
#!/bin/bash # 啓動celery的異步任務與定時任務 /etc/init.d/celeryd start /etc/init.d/celerybeat start # 啓動uwsgi uwsgi --ini vsapp_uwsgi.ini
準備工做作完後,就是編寫源程序的Dockerfile了。在vsapp下創建名爲Dockerfile的文件,其中內容以下:
FROM python:v3.6.3 RUN apt-get update \ && apt-get install -y libmysqlclient-dev \ && apt-get install -y --no-install-recommends \ postgresql-client \ && rm -rf /var/lib/apt/lists/* VOLUME ["/web/vscode"] WORKDIR /web COPY requirements.txt ./ RUN pip3 install -r requirements.txt COPY vsapp_uwsgi.ini ./ COPY celeryconf/celeryd /etc/init.d/ COPY celeryconf/celerybeat /etc/init.d/ COPY celeryd /etc/default/ COPY run_web.sh ./ RUN chmod 777 run_web.sh \ && chmod 777 /etc/init.d/celeryd \ && chmod 777 /etc/init.d/celerybeat \ && chmod 640 /etc/default/celeryd EXPOSE 8000 # CMD ["./run_web.sh"]
最後,整個vsapp下的目錄以下:
編譯鏡像:在vsapp文件夾下運行以下命令:
docker build -t vsapp:v1.0 .
運行容器:鏡像編譯成功後,運行以下命令:
docker run -it --name vsapp_test -p 8000:8000 -v /home/user/vs/vsapp/vscode/:/web/vscode/ -p /home/user/vs/vsapp/celerywork.log:/var/log/celery/worker1.log
若容器運行成功,在該容器中運行shell腳本命令「./run_web.sh」,便可啓動源程序的服務,若期間沒有報錯,則源程序鏡像製做成功。
nginx鏡像的製做只須要從新配置一下nginx的配置文件nginx.conf,以使其可以與源程序對接並加載源程序中的靜態資源文件。
在nginx_vs文件夾下建立名爲nginx.conf的文件,該文件內容以下:
#user www-data; worker_processes 1; #pid /run/nginx.pid; events { worker_connections 1024; ## Default: 1024 } http { # Definethe MIME types for files. include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; upstream django { # server unix:///usr/share/nginx/html/webapp.sock; # 這裏的端口要寫成8000,由於在源程序鏡像中的vsapp_uwsgi.ini中配置的是8000 server 127.0.0.1:8000; # for a web port socket (we'll use this first) } fastcgi_connect_timeout 300; fastcgi_send_timeout 300; fastcgi_read_timeout 300; fastcgi_buffer_size 256k; fastcgi_buffers 16 256k; fastcgi_busy_buffers_size 512k; fastcgi_temp_file_write_size 512k; # configuration of the server server { # the port your site will be served on listen 8090; # the domain name it will serve for server_name 127.0.0.1; # substitute your machine's IP address or FQDN charset UTF-8; access_log logs/myweb_access.log; error_log logs/myweb_error.log; # max upload size client_max_body_size 75M; # adjust to taste # Django media location /static/ { expires 30d; autoindex on; add_header Cache-Control private; alias /usr/share/nginx/html/webapp/static/; # your Django project's static files - amend as required } # Finally, send all non-media requests to the Django server. location / { uwsgi_read_timeout 500; uwsgi_pass django; include /usr/share/nginx/html/webapp/uwsgi_params; # the uwsgi_params file you installed } } } daemon off;
該配置文件實際上是對原nginx中的配置文件進行了更改。主要是聲明瞭內部nginx與uwsgi通信的端口,以及外部正常訪問服務器的端口;源程序的靜態資源文件夾路徑;源程序的的uwsgi_params文件路徑。
在nginx_vs文件夾下創建Dockerfile文件,內容以下:
FROM ubuntu:16.04 RUN apt-get update RUN apt-get install gcc -y RUN apt-get install g++ -y RUN apt-get install make -y RUN apt-get install wget -y RUN wget http://nginx.org/download/nginx-1.14.0.tar.gz && wget https://ftp.pcre.org/pub/pcre/pcre-8.37.tar.gz #RUN cd /usr/local && mkdir src RUN tar -xvf nginx-1.14.0.tar.gz -C /usr/local/src && tar -xvf pcre-8.37.tar.gz -C /usr/local/src WORKDIR /usr/local/src/nginx-1.14.0/ RUN ./configure --prefix=/usr/local/nginx --without-http_gzip_module --with-pcre=/usr/local/src/pcre-8.37 && make && make install ADD nginx.conf /usr/local/nginx/conf/ VOLUME ["/usr/share/nginx/html/webapp/"] ENV PATH /usr/local/nginx/sbin:$PATH EXPOSE 80 8090 8000 ENTRYPOINT ["nginx"]
編譯鏡像:在nginx_vs文件夾下運行命令
docker build -t nginx:v1.0 .
運行容器: 運行命令:
docker run -it --name nginx_test -p 8090:8090 -v /home/user/vs/vsapp/vscode/:/usr/share/nginx/html/webapp nginx:v1.0
redis在該vscode系統中充當的角色是任務隊列,故直接製做原始的redis鏡像便可。不過爲了使咱們能在宿主機上查看redis鏡像運行容器時產生的數據庫數據與log,咱們有必要從新配置redis配置文件redis.conf。
拿到原始的redis.conf修改如下幾處:
# 指定log存放路徑 logfile /data/logs/redis.log # 指定數據庫存放路徑 dir /data/redisData/ # 若鏈接redis須要密碼,則配置如下項 requirepass 1234*
在redis_vs下創建文件夾data,並將修改後的redis.conf放到data中,再在data目錄中創建logs、redisData文件夾,logs文件夾中創建名爲redis.log的文件。整個redis_vs的目錄結構以下:
-- redis_vs -- data -- redisData -- logs -- redis.log -- redis.conf -- Dockerfile
redis的Dockerfile文件內容以下(我這裏安裝的redis版本爲3.0.6):
FROM ubuntu:16.04 RUN apt-get update RUN apt-get install gcc -y RUN apt-get install g++ -y RUN apt-get install make -y RUN apt-get install wget -y RUN \ cd /tmp && \ wget http://download.redis.io/releases/redis-3.0.6.tar.gz && \ tar xvzf redis-3.0.6.tar.gz && \ cd redis-3.0.6 && \ make && \ make install && \ cp -f src/redis-sentinel /usr/local/bin && \ mkdir -p /etc/redis && \ cp -f *.conf /etc/redis && \ rm -rf /tmp/redis-3.0.6* && \ sed -i 's/^\(bind .*\)$/# \1/' /etc/redis/redis.conf && \ sed -i 's/^\(daemonize .*\)$/# \1/' /etc/redis/redis.conf && \ sed -i 's/^\(dir .*\)$/# \1\ndir \/data/' /etc/redis/redis.conf && \ sed -i 's/^\(logfile .*\)$/# \1/' /etc/redis/redis.conf # Define mountable directories. VOLUME ["/data"] COPY data/redis.conf . # Define working directory. WORKDIR /data # Define default command. # CMD ["redis-server", "redis.conf"] # Expose ports. EXPOSE 6379
編譯鏡像: 在redis_vs目錄下運行命令:
docker build -t redis:v1.0 .
運行容器: 運行以下命令:
docker run -it --name redis_test -p 6379:6379 -v /home/user/vs/redis_vs/data/:/data/ redis:v1.0
當進入到容器中,在容器中運行命令「redis-server redis.conf」便可啓動redis服務。
如今全部的鏡像都已編譯成功,下面就是將這些鏡像所運行的容器聯合起來以搭建成系統。這裏咱們採用docker-compose對這些鏡像進行編排。
在vsapp下創建名爲docker-compose.yml的文件,其內容以下:
version: '3' services: mongodb: image: mongodb:v1.0 ports: - "27017:27017" - "27018:27018" volumes: - "$PWD/mongodb_vs/data/db/:/data/db" - "$PWD/mongodb_vs/data/log/:/data/log/" command: ["./start_mongo.sh"] webapp: image: vsapp:v1.0 network_mode: "host" ports: - "8000:8000" volumes: - "$PWD/vsapp/vscode/:/web/vscode/" - "$PWD/vsapp/celerywork.log:/var/log/celery/worker1.log" depends_on: - mongodb - nginx - redis command: ["./run_web.sh"] nginx: image: nginx:v1.0 network_mode: "host" ports: - "8090:8090" volumes: - "$PWD/vsapp/vscode/:/usr/share/nginx/html/webapp" redis: image: redis:v1.0 network_mode: "host" ports: - "6379:6379" volumes: - "$PWD/redis_vs/data/:/data/" command: ["redis-server","redis.conf"]
此時,docker-compose已經編寫完成,下面就是利用docker-compose運行這些容器了
運行命令:
docker-compose up
若運行後沒有報錯,說明整個系統已經搭建並啓動成功。能夠對該系統進行訪問嘗試。
將系統進行docker化其實就是從新對原來的系統進行了一個在新機器上的配置,只不過配置的能夠分應用一個個配置了。