docker容器化python服務部署(supervisor-gunicorn-flask)

          docker容器化python服務部署(supervisor-gunicorn-flask)

                    本文系作者原創,轉載請註明出處: https://www.cnblogs.com/further-further-further/p/13223767.html

 

目錄

  •  實現目標

  •  docker vs virtual machine(虛擬機)

  •  實戰(python 服務鏡像製作,本地鏡像倉庫創建,移植)

  •  遇到的問題以及解決辦法

 


 

 

  • 實現目標 

>  在局域網內機器上部署 python 服務(在某臺機器上部署完成後,生成鏡像,上傳到本地鏡像倉庫,其他機器下載鏡像,一鍵部署服務);

> 開機自啓動(物理機啓動->容器自啓動->服務自啓動)

 

  • docker vs virtual machine(虛擬機)

 啥也不說,先上docker官方網站的兩張圖。

 

 

 VM(虛擬機)

優點:在於隔離性,各個虛擬環境之間是完全隔離的。

缺點:每個虛擬環境類似於一個獨立的機器,有獨立的操作系統,所以佔用內存比較大,一臺物理機器最多也就能同時開啓虛擬環境 10+,

          另外,部署在虛擬環境下服務不太好移植。

docker 

優點:有虛擬機隔離性的特點,解決了傳統 VM 佔用內存較大,服務不太好移植的問題。

關於 vm 和 docker 的詳細區別,這裏就不贅述了,網絡上鋪天蓋地,大家隨便百度一下。

 

  • 實戰(python 服務鏡像製作,本地鏡像倉庫創建,移植)

我的操作系統linux centos7,通過命令 cat /etc/os-release 查看

 

        

> docker 安裝

注:宿主機 centos 版本最好是 7 以上,在 6 上安裝 docker 遇到坑比較多。

yum install -y docker

> 獲取基礎鏡像

docker pull centos  

會自動在官網(https://hub.docker.com/)獲取 centos:latest 鏡像。

查看所有鏡像(-a : all):

docker image ls -a

> 容器創建

docker container run -it -p 8888:8080 -v /opt/app:/opt/app --name=python-server 470671670cac bash

命令文檔查看:docker container run --help

-it : 交互式終端(interactive terminal) ,也就是創建容器後進入容器。

-p 8888:8080 :  端口映射(port),將容器端口映射到宿主機端口(8888:宿主機端口,8080:容器端口),宿主機端口 8888 確認能被外網訪問。

-v /opt/app:/opt/app:數據卷(volumn),將宿主機的數據(應用程序代碼,配置文件等等)掛載到容器指定路徑下,實現數據存儲的持久化(如果沒有數據掛載的話,容器銷燬,容器中的數據會自動消失)。

--name=python-server: 新的容器的名稱

 470671670cac:鏡像ID(imageID),當然也可以是 imageName + tag(docker.io/centos:latest)

bash:跟 -it 命令結合在一起操作,使容器創建後處於前端,一般是 /bin/bash,我這是bash。

表示容器已創建完成,並已進入容器,容器ID:5de4e81a2e20

可以通過 Ctrl+p,Ctrl+q 退出容器,但容器還是處於運行狀態(Up)。

查看正在運行容器的狀態:docker container ls 也可以是 docker ps

 

查看所有容器的狀態(包含正在運行 up 和停止 exit):docker container ls  -a  == docker ps -a

退出容器後再進入容器,有兩種方式(前提是該容器必須處於運行狀態):

方式一:docker container exec -it 5de4e81a2e20(containerID) bash

方式二:ssh 172.17.0.4(容器ip)

查看容器ip(需要退出容器查看)

docker container inspect 5de4e81a2e20(containerID)

 

容器其他相關操作命令:

容器啓動(交互式):docker container start  -i containerID

關閉容器:docker container stop containerID

容器重啓動:docker container restart containerID

刪除容器(-f : force 強制刪除,能刪除處於運行狀態的容器):docker container rm -f  containerID

查看所有容器的容器ID:docker container ls -a -q

刪除所有容器:docker contianer rm $(docker container ls -a -q)

在交互式容器中退出,退出啓動容器: Ctrl + d

 在交互式容器中退出,但是不退出啓動容器:先按 Ctrl + p 後 Ctrl + q

使用 -d 啓動容器並一直在後臺運行 SSH作爲第一進程啓動:docker container run -d -p 50001:22 imageID /usr/sbin/sshd -D

 > 安裝 SSH:

SSH作用:

1. 出現問題方便進入容器調試;

2. 作爲 python 服務的守護程序,防止容器閃退(一直夯在容器中);

安裝命令: yum install -y openssh-server

ssh 配置文件 sshd_config 路徑: /etc/ssh/

ssh 啓動文件路徑:/usr/sbin/

安裝 passwd(設置密碼): yum install -y passwd

設置密碼:passwd root

new password: 12345678

啓動 SSH: /usr/sbin/sshd

查看容器 ip(退出容器,在宿主機上,最好另起一個客戶端): docker container inspect  1427087a62a7(containerID)

 

從宿主機進入容器:ssh 172.17.0.5 ,輸入密碼:12345678

> 安裝 python3:

一般只需安裝 pip3即可,但是爲了服務調試,這裏安裝了python3,python3中包含了pip。

安裝命令:yum install -y python3

安裝完成後,查看版本:python3 -V

   

這裏的python服務是關於深度學習的,所以需要添加庫opencv,flask,interval,matplotlib,Pillow,gunicorn,gevent,supervisor。

安裝 python 相關庫

通過pip3安裝,最好加上國內鏡像源,防止網絡的原因無法下載。

國內常用鏡像源:

阿里雲 http://mirrors.aliyun.com/pypi/simple/

中國科技大學 https://pypi.mirrors.ustc.edu.cn/simple/

豆瓣(douban) http://pypi.douban.com/simple/

清華大學 https://pypi.tuna.tsinghua.edu.cn/simple/

中國科學技術大學 http://pypi.mirrors.ustc.edu.cn/simple/

>> opencv:

pip3 install opencv-python-headless==4.2.0.32 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com

>> flask:

pip3 install Flask==1.1.2 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com

>> interval:

pip3 install interval==1.0.0 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com

>> matplotlib:

pip3 install matplotlib==3.2.1 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com

>> gunicorn

pip3 install gunicorn==20.0.4 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com

>> supervisor

pip3 install supervisor==4.0.0 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com

>> gevent:

pip3 install gevent==20.6.0 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com

當然也可以通過 requirements.txt 一鍵安裝所有相關庫:

將 python 相關庫寫入 requirements.txt中:

cat > requirements.txt <<EOF

certifi==2020.4.5.2
chardet==3.0.4
click==7.1.2
cycler==0.10.0
Flask==1.1.2
gevent==20.6.0
gpg==1.10.0
greenlet==0.4.16
gunicorn==20.0.4
idna==2.9
interval==1.0.0
itsdangerous==1.1.0
Jinja2==2.11.2
kiwisolver==1.2.0
MarkupSafe==1.1.1
matplotlib==3.2.1
meld3==2.0.1
numpy==1.18.5
opencv-python-headless==4.2.0.32
Pillow==7.1.2
pyparsing==2.4.7
python-dateutil==2.8.1
requests==2.23.0
rpm==4.14.2
six==1.15.0
supervisor==4.0.0
urllib3==1.25.9
Werkzeug==1.0.1
zope.event==4.4
zope.interface==5.1.0

EOF

查看:cat requirements.txt

一鍵安裝:pip3 install -r requirements.txt

如果已安裝完所有庫,需要移植到其他機器中,打包所有 python 庫:pip3 freeze > requirements.txt

> supervisor & gunicorn 配置

gunicorn 可以理解爲 WSGI 協議的一個實例,WSGI(Web Server Gateway Interface):就是一個網關,是 web 服務器與應用程序之間通信的協議接口。

supervisor 提供了統一的方式來控制(start,stop,restart)進程,類似於 systemctl(在 docker 容器中 systemctl 命令是無效的)。 

>> 生成 supervisord.conf

 echo_supervisord_conf > /etc/supervisord.conf

>> 修改 supervisord.conf 配置

vi /etc/supervisord.conf   

在文件最底部,去掉 include , files 註釋,並將 files 修改爲

[include]
files = /etc/supervisor/*.conf

>> 添加 gunicorn.conf

創建路徑:mkdir /etc/supervisor

創建配置文件 gunicorn.conf:vi /etc/supervisor/gunicorn.conf

內容爲:

[program:gunicorn]
command = gunicorn -c /opt/app/darknet_captcha/gunicorn.conf.py wsgi:application
autostart = true
startsecs = 5
autorestart = true
startretries = 3
redirect_stderr = true
stdout_logfile=/opt/app/logs/gunicorn.log   

>> 配置文件生效:supervisorctl update

>> 先測試 gunicorn 啓動 flask 服務

gunicorn -c /opt/app/darknet_captcha/gunicorn.conf.py wsgi:application

psc -ef|grep gunicorn

說明啓動正常

刪除 gunicorn 進程,改由 supervisord 啓動

kill -9  55

>> 用 supervisord 啓動 gunicorn

supervisord -c /etc/supervisord.conf

如果出現如下問題,說明已有進程啓動,佔用了端口號。

解決辦法:刪除已啓動進程即可

ps -ef|grep supervisord

kill -9 pid

啓動後,查看 gunicorn 是否啓動。

ps -ef|grep gunicorn

如果服務啓動失敗,在日誌裏查看原因。

日誌查看:vi /opt/app/logs/gunicorn.log 

後面就可以使用如下命令操作gunicorn
supervisorctl start gunicorn
supervisorctl stop gunicorn
supervisorctl restart gunicorn

到此,在單機上 docker 容器下 flask 服務部署已完成,接下來就是

基本鏡像的製作,通過 dockerfile 創建最終鏡像,本地鏡像倉庫創建,鏡像 push 到本地倉庫,局域網內其他機器 pull 鏡像,一鍵部署服務。

> 基本鏡像製作

退出容器,但容器需處於運行(up)狀態:Ctrl + p,Ctrl + q

查看容器ID: docker container ls

製作鏡像(鏡像名稱:weixw/python-server-mirror:v1):docker commit c96c249cf2bd weixw/python-server-mirror:v1

用 docker image ls 查看新鏡像是否已存在

> 通過 dockerfile 創建最終鏡像

爲什麼還要通過 dockerfile 製作鏡像呢,因爲上面生成的基礎鏡像只能保存靜態文件,資源,不能保存動態命令,比如 shell 相關命令,應用程序命令,

而這些命令可以通過 dockerfile 寫入進來,從而達到一鍵創建容器就能自動啓動服務的目的。

>> 創建 Dockerfile (規範名稱必須是 Dockerfile 或 dockerfile)

在應用程序服務的根目錄下創建 Dockerfile :

cd /opt/app/darknet_captcha

vi Dockerfile

 >> Dockerfile 內容

FROM: 基礎鏡像

WORKDIR:  指定當前路徑

COPY: 複製文件

ADD : 添加文件,有 COPY 功能,還有解壓,從網站下載文件作用

EXPOSE: 暴露容器端口

CMD : shell 以及 應用程序命令

>> init.sh()

 CMD 一般只能運行一條命令,對於多個命令,採用腳本方式運行。

>> 創建最終鏡像

cd /opt/app/darknet_captcha

docker image build -t weixw/python-server-mirror:v1.2 ./

 查看:docker image ls

> 本地鏡像倉庫創建(其他端口不太行,需要開啓外網訪問端口5000):

>> 下載 registry 鏡像

docker pull registry

>> 啓動registry容器:docker run -d -p 5000:5000 --restart=always --name registry -v /opt/registry/:/var/lib/registry registry

--restart=always : docker 啓動,容器自啓動

>> 修改docker 配置文件 daemon.json

vim /etc/docker/daemon.json
{
"registry-mirrors":["https://uoggbpok.mirror.aliyuncs.com"],
"insecure-registries":["120.132.8.180:5000"]
}

>> 本地倉庫加安全認證

>>> 生成密碼:username: root     password: 123456

yum install httpd-tools -y
mkdir /opt/registry-auth/ -p
htpasswd -Bbn root 123456 > /opt/registry-auth/htpasswd

>>> 修改密碼:
cd /opt/registry-auth/
vim htpasswd

>>> 重新啓動帶有祕鑰功能的registry容器
docker rm -f containerID
docker run -d -p 5000:5000 -v /opt/registry-auth/:/auth/ -v /opt/registry:/var/lib/registry --restart=always --name register-auth -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" registry

>>> 規範本地鏡像名稱:docker tag  imageID   120.132.8.180:5000/weixw/captcha

docker tag weixw/python-server-mirror:v1 120.132.8.180:5000/weixw/python-server-mirror:v1.2

>>> 登錄(一定要先登錄校驗,否則無法 push):
docker login 120.132.8.180:5000
username: root
password: 123456

>>> 上傳鏡像到本地倉庫(端口5000能被外網訪問):docker push 120.132.8.180:5000/weixw/python-server-mirror:v1.2

有一個 harbor 服務用來可視化管理鏡像的,大家感興趣的話可以玩玩,因爲我的Linux宿主機本來就是虛擬機,配置比較低,這裏就不安裝了。

> 另外一臺機器獲取鏡像( 120.132.8.180:5000)步驟:

>> 修改docker 配置文件 daemon.json
vim /etc/docker/daemon.json
{
"registry-mirrors":["https://uoggbpok.mirror.aliyuncs.com"],
"insecure-registries":["120.132.8.180:5000"]
}

>> 重啓 docker : systemctl restart docker

>> 登錄(pull 一般不需要登錄,可以直接下載):

docker login 120.132.8.180:5000
username: root
password: 123456

>> 向鏡像倉庫(120.132.8.180:5000)獲取鏡像: docker pull 120.132.8.180:5000/weixw/python-server-mirror

>> 一鍵啓動服務:docker container run -d -p 80:8080 --restart=always --name=captcha_server 120.132.8.180:5000/weixw/python-server-mirror

-d: 表示在後臺啓動

-p: 表示端口映射(80:宿主機端口,8080:容器端口)

--restart=always:表示開機自啓動容器

 啓動容器後查看 flask 服務是否啓動:ps -ef|grep gunicorn

用 curl 或 postman 向 120.132.8.180:80/服務名稱 發送請求,查看結果。

如果服務沒有起來,查看日誌/opt/app/logs/gunicorn.log 定位問題,然後解決問題。

  •  遇到的問題以及解決辦法

> 無法強制刪除鏡像

原因:該鏡像下有容器創建,有可能不是運行狀態(exit),所以需要先刪除容器,再刪除鏡像。

解決方案:

查找所有容器:dokcer container ls -a

刪除該鏡像下所有容器:docker container rm -f containerID

刪除鏡像:docker image rm -f imageID

> 鏡像也可以保存文件,然後將文件導入

>> 將鏡像保存在本地:docker save -o 本地名字 image/name

例如: docker save -o python-server.tar 120.132.8.180:5000/weixw/python-server-mirror

>> 將本地鏡像文件加載進docker: docker load -i python-server.tar

 

 

不要讓懶惰佔據你的大腦,不要讓妥協拖垮了你的人生。青春就是一張票,能不能趕上時代的快車,你的步伐就掌握在你的腳下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章