Docker構建nginx+uwsgi+flask鏡像(二)


Dockerfile搭建環境並打包應用

在上一章Docker構建nginx+uwsgi+flask鏡像(一)的學習中,我們學會用命令行一句一句在alpine環境中搭建nginx+uwsgi+flask服務,但這體現不了Docker為我們帶來的便利,而本章,我們將通過Dockerfile來制作基礎鏡像和打包應用,因此會有兩個Dockerfile文件。

我們先來寫第一個Dockerfile文件,這個文件負責搭建運行環境,運行環境需要包括:nginx、uwsgi、Python3:

# 配置基礎鏡像
FROM alpine:3.8

# 添加標簽說明
LABEL author="moshangguang" email="XXX@qq.com"  purpose="nginx+uwsgi+Python3基礎鏡像"

# 配置清華鏡像地址
RUN echo "https://mirror.tuna.tsinghua.edu.cn/alpine/v3.8/main/" > /etc/apk/repositories

# 更新升級軟件
RUN apk add --update --upgrade

# 安裝軟件
RUN apk add --no-cache nginx python3 uwsgi uwsgi-python3 

# 升級pip,這一步同時會在/usr/bin/目錄下生成pip可執行文件
RUN pip3 install --no-cache-dir --upgrade pip

# 建立軟鏈接
RUN ln -s /usr/bin/python3 /usr/bin/python

     

上面的安裝軟件相比之前少了個vim,因為之前我們是在容器內部編輯配置文件,所以需要這個命令,但現在我們的配置文件都是預先在容器之外編輯好在通過docker拷貝到容器內部,所以也就無需安裝vim。另外建立軟連接時,我們只建立了從python到python3的軟連接,沒有建立pip到pip3的軟鏈接,因為/usr/bin/pip在安裝軟件時已經生成。

執行docker build命令,生成鏡像,執行docker images命令可以看到生成nginx_uwsgi_py3鏡像,標簽為alpine3.8:

[root@ docker]# docker build -t nginx_uwsgi_py3:alpine3.8 .
Sending build context to Docker daemon 4.096 kB
……
Successfully built 63be35fe36ca
[root@ docker]# docker images
REPOSITORY                       TAG                   IMAGE ID            CREATED             SIZE
nginx_uwsgi_py3                  alpine3.8             63be35fe36ca        5 minutes ago       60 MB

  

於是,我們完成了第一個Dockerfile文件,這個Dockerfile文件可以為我們搭建我們所需要的運行環境鏡像。

我們可以把構建好的基礎鏡像推送到我們的Docker hub倉庫,先用docker login登錄之后

[root@ docker]# docker login -u moshangguang -p 123456
Login Succeeded

  

tips:上面登錄密碼是假的哈。

然后為我們的鏡像打上tag,之后推送鏡像。

[root@ docker]# docker tag 687445ba4c7f moshangguang/nginx_uwsgi_py3:alpine3.8
[root@ docker]# docker images
REPOSITORY                       TAG                   IMAGE ID            CREATED             SIZE
moshangguang/nginx_uwsgi_py3     alpine3.8             63be35fe36ca        22 minutes ago      60 MB
nginx_uwsgi_py3                  alpine3.8             63be35fe36ca        22 minutes ago      60 MB
[root@iZj6c0zloujsauztjjhyhgZ docker]# docker push moshangguang/nginx_uwsgi_py3:alpine3.8
The push refers to a repository [docker.io/moshangguang/nginx_uwsgi_py3]
……
alpine3.8: digest: sha256:412ec97c1c51dffeee6b924494bc size: 1154

  

有了基礎鏡像,我們就可以開始編寫我們的應用了,這里先給出我們應用的目錄結構(web_app在github上的地址):

[root@ docker]# tree web_app
web_app
├── app
│   ├── app.py
│   ├── requirements.txt
│   └── uwsgi.ini
├── Dockerfile
└── nginx.conf

1 directory, 5 files

  

最外層的web_app目錄包含一個app目錄,和兩個文件,分別是Dockerfile、nginx.conf,注意,web_app下的Dockerfile文件和之前的Dockerfile文件不同,這里的Dockerfile文件是用來打包應用的。nginx.conf文件在打包應用時會拷貝到容器中,作為nginx啟動的配置。

app目錄下有三個文件,分別是:app.py、requirements.txt和uwsgi.ini。我們唯一不熟悉的就是requirements.txt,這個文件用來存放我們Python應用所需要的庫,如flask、flask_sqlalchemy等等。在打包應用時會執行pip命令讀取這個文件的內容,安裝我們所需要的庫。

這里,我們打印下requirements.txt的內容:

[root@ app]# cat requirements.txt 
flask
flask_sqlalchemy

  

app.py文件也略做修改,新增兩個路由/hello和/world:

from flask import Flask

app = Flask(__name__)


@app.route('/hello')
def hello():
    return 'Hello!!!\n'


@app.route('/world')
def world():
    return 'World!!!\n'


@app.route('/')
def hello_world():
    return 'Hello World!!!\n'


if __name__ == '__main__':
    app.run()

  

上一章中,我們在uwsgi.ini文件中將uwsgi-socket配置綁定到本機的9000端口,同時在nginx.conf文件中設置uwsgi_pass,將請求轉發到9000端口,這樣的做法顯得有些累贅,如果以后我不想用9000端口,意味着我需要改兩個地方。那么,有沒有辦法讓uwsgi自動獲取綁定到一個端口,而nginx.conf又能獲取到uwsgi所綁定的端口呢?肯定是有的:

uwsgi.ini

[uwsgi]
uwsgi-socket    = /tmp/uwsgi.sock
chmod-socket    = 777
callable        = app
plugin          = python3
wsgi-file       = app.py
buffer-size     = 65535
processes       = %(%k * 2)
threads         = %(%k * 20)
disable-logging = true

    

上面的uwsgi.ini文件中,我們不再將uwsgi-socket這個配置項綁定到特定的一個端口,而是指定了一個文件,這個文件是Unix套接字,即通過文件系統(而非網絡地址)進行尋址和訪問的套接字。配置uwsgi-socket之后,還需要配置chmod-socket,Unix socket是個文件,所以會受到Unix系統的權限限制,可以配置成660或者777,使得uwsgi客戶端能夠訪問這個Unix socket文件,這里配置為777。

這里新增兩個優化參數:processes和threads,分別是開啟的進程數和線程數,而%k是魔數變量,代表CPU核數,如果我們是雙核CPU,那這里的processes和threads分別為4和40,即有4個進程,每個進程有40個線程。disable-logging的意思一目了然,代表不記錄請求信息的日志,只記錄錯誤以及uwsgi內部消息到日志中。

最后,我們再來看下nginx.conf需要做改動的地方,其實也就是http模塊下的server:

server {
  listen 6666;
  charset utf-8;
  client_max_body_size 75M;
  location / {
	include uwsgi_params;
	uwsgi_pass unix:///tmp/uwsgi.sock;
        ……
  }
}

  

其實改動的地方也只有一個uwsgi_pass,原先我們是直接綁定在9000端口上,而現在我們要指向uwsgi-socket所指向的Unix套接字。這樣,nginx就可以自動將請求轉發給uwsgi所監聽的套接字了。

這里給出nginx.conf全部的內容:

user  nginx;
worker_processes  1;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;
worker_rlimit_nofile 20480;


events {
  use epoll;
  worker_connections 20480;
  multi_accept on;
}


http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    #請求量級大建議關閉acccess_log
    #access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  300s;
    client_header_timeout 300s;
    client_body_timeout 300s;

    gzip on;
    gzip_min_length 1k;
    gzip_buffers 4 16k;
    gzip_types text/html application/javascript application/json;

    include /etc/nginx/conf.d/*.conf;

    server {
      listen 6666;
      charset utf-8;
      client_max_body_size 75M;
      location / {
        include uwsgi_params;
        uwsgi_pass unix:///tmp/uwsgi.sock;
        uwsgi_send_timeout 300;
        uwsgi_connect_timeout 300;
        uwsgi_read_timeout 300;
      }
    }
}

  

最后,我們來看下用於打包應用的Dockerfile:

# 使用基礎鏡像庫
FROM moshangguang/nginx_uwsgi_py3:alpine3.8

# 創建工作路徑
RUN mkdir /app

# 指定容器啟動時執行的命令都在app目錄下執行
WORKDIR /app

# 替換nginx的配置
COPY nginx.conf /etc/nginx/nginx.conf

# 將本地app目錄下的內容拷貝到容器的app目錄下
COPY ./app/ /app/

# pip讀取requirements.txt內容安裝所需的庫
RUN pip install -r /app/requirements.txt -i  https://pypi.tuna.tsinghua.edu.cn/simple some-package --no-cache-dir

# 啟動nginx和uwsgi
ENTRYPOINT nginx -g "daemon on;" && uwsgi --ini /app/uwsgi.ini

  

上面的每一條命令都有注釋,這里就不再多作介紹了。

現在,讓我們來打包web_app應用吧!將工作目錄移到web_app目錄下,執行docker build命令,創建鏡像:

[root@ web_app]# docker build -t web_app .
Sending build context to Docker daemon 24.58 kB
……
Successfully built 88212eefb0b4

 

查看剛剛創建的web_app鏡像:

[root@ web_app]# docker images
REPOSITORY                       TAG                   IMAGE ID            CREATED              SIZE
web_app                          latest                88212eefb0b4        About a minute ago   79.9 MB

  

根據鏡像啟動一個容器,容器內部的nginx監聽的是6666端口,而宿主機則用9999端口接收請求,再轉發到容器內部的6666端口:

[root@ web_app]# docker run -p 9999:6666 -d web_app
a8cd1104dfc994637011ebd9dd9160d62eab64b1c9bb6ceb9266c092eb425452

  

這里,測試容器內的應用是否能正常處理用戶的請求:

 

 

 

 

 

到此為止,我們便完成了用Docker構建基礎鏡像,並打包應用了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM