基于Docker的Django-Mysql-Apache應用容器化
2017-05-25
<span id = "1">
Mysql的容器
</span>
Mysql有官方發布的鏡像,可以直接拉取,并按需求啟動一個容器。
參考:這里
啟動一個容器
docker run --name mysql-container -v /root/mysql_datadir:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql/mysql-server:5.7
啟動一個5.7版本的Mysql容器,環境變量MYSQL_ROOT_PASSWORD表示superuser的密碼,掛載宿主機的目錄作為容器Mysql的數據存儲目錄。如果是第一次運行,Docker會發現本地沒有Mysql鏡像,會進行相應的依賴的拉取,隨機啟動容器。

docker ps -al

可以看出,mysql的容器依然暴露3306端口。
接入容器
docker exec -it mysql-container mysql -uroot -proot

成功接入mysql容器,創建成功。
查看Mysql的日志
容器的Mysql日志存儲在/var/log/mysqld.log下
掛載宿主機目錄作為Mysql的存儲路徑,并映射宿主機端口到容器外部端口
docker run --name mysql-container -p 3307:3306 -v /root/mysql_datadir:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql/mysql-server:5.7
將/root/mysql_datadir目錄掛載進/var/lib/mysql作為數據庫存儲文件。映射宿主機3307端口到容器3306端口。容器啟動后,mysql_datadir目錄下會產生新文件

注意: 宿主機的目錄必須要是絕對路徑
當容器宕掉后,被清除后。重新啟動一個Mysql容器,并掛載 mysql_datadir 作為數據庫存儲路勁時,記得忽略MYSQL_ROOT_PASSWORD環境變量的設置。先前存在的數據庫文件不會有變化。
有時由于SElinux,讀寫目錄會有沖突,敲入以下命令
chcon -Rt svirt_sandbox_file_t /root/mysql_datadir
進入容器配置數據庫權限
docker exec -it mysql-container mysql -uroot -proot
grant all privileges on *.* to 'root'@'192.168.31.182' identified by 'root' with grant option;
從192.168.31.182可以訪問這個容器的mysql服務
mysql -h[hostIP] -P3307 -uroot -p

<span id="2">
Django容器化
</span>
從DockerHub上拉取Django鏡像
docker pull library/Django:1.10.4-python3
需要等待一段時間

這個鏡像已經配置好了python3.4和django1.10的環境。現在我們還要構建可以連接mysql的環境。
用Dockerfile文件構建一個鏡像
新建一個Dockerfile文件,添加下面內容

build鏡像
docker build -t [倉庫和標簽名稱] [Dockerfile文件路徑]


從鏡像運行容器
docker run --name botmail --link mysql-container:db -v /root/docker_study/django_docker/botmail/:/var/www/ -p 8000:7000 -it 1015010127/botmail:v1 /bin/bash
啟動一個名為botmail的容器,并且掛載代碼文件到容器中,同時映射宿主機8000端口到容器的7000端口。連接MySQL的容器,并設置別名為db。
修改Django項目中的settings.py文件中的有關數據庫連接的配置

注意: 同時要為當前容器的ip配置數據庫權限,否則無法連接。
從鏡像中啟動django項目
docker exec -it botmail python manage.py runserver 0.0.0.0:7000

確保防火墻關閉后可以從外部訪問。
這樣構建的Django+mysql容器連接有一些問題,首先端口7000使用了硬編碼,而且數據庫連接使用‘db’硬編碼,應當考慮使用docker-compose
使用docker-compose搭建MySQL+django
安裝docker-compose,參考:官方安裝文檔
curl -L https://github.com/docker/compose/releases/download/$dockerComposeVersion/docker-compose-`uname -s\`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
建立一個目錄botmail_docker,并新建一個docker-compose.yml文件,寫入以下內容。
1 # docker-compose版本
2 version: '3'
3 # 服務
4 services:
5 # 數據庫服務
6 db:
7 # 拉取鏡像
8 image: 1015010127/mysql-server:v2
9 # 運行容器的名稱
10 container_name: mysql-container
11 # 環境變量文件
12 env_file: ./db.env
13 # 端口映射,外部可以從3308端口訪問
14 ports:
15 - "3308:3306"
16 # 掛載目錄
17 volumes:
18 # 數據儲存目錄,請自行定義
19 - /root/docker_study/botmail_docker/data:/var/lib/mysql
20 # 設置工作目錄
21 working_dir: /mysql_data_init
22 # web服務
23 web:
24 image: 1015010127/botmail:v1
25 container_name: botmail
26 # 依賴db服務,先啟動db再啟動web
27 depends_on:
28 - db
29 # 宕機即重啟
30 restart: always
31 # 暴露端口
32 ports:
33 - "8000:7000"
34 volumes:
35 - ./botmail:/var/www/botmail # 代碼文件
36 working_dir: /var/www/botmail
37 # 啟動容器是運行的命令
38 command: python manage.py runserver 0:7000
39 # 連接數據庫
40 links:
41 - db
創建db.env文件用作設置db服務的環境變量。
1 # 指定root的密碼
2 MYSQL_ROOT_PASSWORD=root
3 # 創建一個新的數據庫
4 MYSQL_DATABASE=botmail_docker
5 # 指定某個網段的ip可以訪問
6 MYSQL_ROOT_HOST=172.%.%.%
7 # 要掛載的數據存儲位置
8 MYSQL_VOLUME_DATADIR=/root/docker_study/botmail_docker/data
9 # 數據庫初始化數據
10 MYSQL_INIT_DIR=/root/docker_study/botmail_docker/mysql_init/botmail_online.sql
11 # 運行時執行的
12 EXEC_SQL=use botmail_docker;source data_init.sql;
創建data文件夾用作db服務的數據存儲,通過以下命令啟動容器組合。
docker-compose up
若是data文件夾中為空,db服務會進行一些初始化

啟動成功后,通過docker-compose ps
可以查看運行的容器,注意: 要在docker-compose.yml文件目錄下敲命令。

現在可以從宿主機的ip訪問botmail應用,但因為數據庫中沒有數據,需要初始化數據。
docker-compose exec db mysql -uroot -proot -e "use botmail_docker;source data_init.sql;"
data_init.sql文件已經存在在數據庫容器的工作目錄下。

現在可以進行登錄了。
<span id="3">
Apache容器
</span>
拉取centos鏡像,用來搭建apache服務

啟動一個容器,并用yum安裝httpd服務


啟動httpd服務報錯

這個問題可以參考后面的錯誤解決辦法
此時先不管這個問題
安裝django環境
安裝python3
pip安裝django1.10以及pymysql

配置apache的python模塊
安裝mod_wsgi
wsgi全稱為web server gateway interface,是web應用與服務器的接口模塊,apache必須安裝mod_wsgi才能夠和python代碼進行交互,之前有個版本用的是mod_python,現已經淘汰了
下載源碼包
wget https://github.com/GrahamDumpleton/mod_wsgi/archive/4.5.15.tar.gz
解壓并編譯安裝
解壓并安裝,注意提前安裝gcc和httpd-devel,這是編譯所必須的依賴包,否則編譯報錯(apx:commmand not found)
yum install gcc httpd-devel -y
編譯安裝mod_wsgi,注意指定python3的環境

成功編譯安裝的結果

說明模塊已經安裝到這個目錄下了/usr/lib64/httpd/modules/mod_wsgi.so
在httpd的模塊目錄中可以找到

卸載依賴包,減小容器的體積
測試apache服務
剛剛遇到了apache服務無法啟動的問題,現在進行解決
退出容器,將當前容器打包成鏡像
docker commit -pm "新版apache_django配置" apache 1015010127/centos:apache_v4
最后一個選項是我的docker倉庫名,可以自行定義
用以下新命令運行
docker run --privileged -d --name apache -p 6003:80 1015010127/centos:apache_v4 /usr/sbin/init

進入容器,啟動apache服務

通過瀏覽器可以訪問

6003端口是宿主機的,映射到容器的80端口
修改httpd.conf文件
添加以下兩行
導入wsgi模塊
LoadModule wsgi_module modules/mod_wsgi.so
django項目路徑
WSGIPythonPath /var/www/botmail
python3的安裝路徑
WSGIPythonHome /usr/python3.5
配置虛擬主機
在/etc/httpd/conf.d/目錄下新建一個文件botmail.conf,添加以下內容
<VirtualHost *:80>
WSGIScriptAlias / /var/www/botmail/botmail/wsgi.py
#WSGIPythonPath /var/www/botmail
#WSGIPythonHome /usr/python3.5
Alias /media/ /var/www/botmail/media/
Alias /static/ /var/www/botmail/html/dist/static/
<Directory /var/www/botmail/media>
Require all granted
</Directory>
<Directory /var/www/botmail/html/dist/static/>
Require all granted
</Directory>
<Directory /var/www/botmail/botmail>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
</VirtualHost>
注意: 不要在虛擬主機的配置文件中配置WSGIPythonPath和WSGIPythonHome,否則啟動apachectl服務時報錯
因為是第一次接觸apache服務器,這里的配置具體含義我不是特別清楚,有興趣應該查閱官方文檔。
重新啟動apache服務,沒錯誤的話就ok
apachectl restart
重新將這個容器打包一份鏡像
現在就剩最后一步了:掛載botmail的項目路徑
通過docker-compose.yml文件構建容器組合
創建一個docker-compose.yml文件,填入以下內容
# docker-compose版本
version: '3'
# 服務
services:
# 數據庫服務
db:
# 拉取鏡像
image: 1015010127/mysql-server:v2
# 運行容器的名稱
container_name: mysql-container
# 環境變量文件
env_file: ./db.env
# 端口映射,外部可以從3308端口訪問
ports:
- "3308:3306"
# 掛載目錄
volumes:
# 數據儲存目錄,請自行定義
- /root/docker_study/botmail_docker/data:/var/lib/mysql
# 設置工作目錄
working_dir: /mysql_data_init
# web服務
web:
image: 1015010127/centos:apache_v5
container_name: botmail_apache
# 依賴db服務,先啟動db再啟動web
depends_on:
- db
# 宕機即重啟
restart: always
# 暴露端口
ports:
- "8000:7000"
- "6001:80"
volumes:
- /root/docker_study/botmail_docker/botmail:/var/www/botmail
working_dir: /var/www/botmail
command: /usr/sbin/init
privileged: true
# 連接數據庫
links:
- db
在這個文件的目錄下運行以下命令
docker-compose up

在瀏覽器上訪問6001端口,即可看到你的django項目

可能會遇到的錯誤
apache配置錯誤
<span id=4>
1. 在centos7鏡像中安裝httpd服務,啟動報錯
</span>

打包當前容器,成鏡像,然后從新用以下命令運行
docker run --privileged -d --name apache -p 6003:80 1015010127/centos:apache_v4 /usr/sbin/init

進入容器,啟動apache服務

通過瀏覽器可以訪問

6003端口是宿主機的,映射到容器的80端口
之后進入容器內啟動apache可以成功
2. apache的python環境配置錯誤
因為python項目是用python3寫的,我們都知道python3和python2是不兼容的,如果apache的是python2環境,如下,啟動時通過查看/var/log/httpd/error_log日志可以查看apache啟動的配置信息

訪問web應用時,后端的python代碼報錯

python2的模塊和python3并不兼容
在httpd/conf/httpd.conf添加Python3的安裝目錄,來指定使用python3的環境

但是在運行的時候卻出現沒有site模塊的錯誤:ImportError: No module named site

現在查看wsgi是否配置正確,/etc/httpd/modules/mod_wsgi模塊的依賴
ldd mod_wsgi.so

依賴的python竟然是python2,因此考慮利用python3環境編譯mod_wsgi模塊
下載源碼包
wget https://github.com/GrahamDumpleton/mod_wsgi/archive/4.5.15.tar.gz
解壓并安裝,注意體檢安裝gcc和httpd-devel,這是編譯所必須的依賴包,否則編譯報錯
yum install gcc httpd-devel -y
編譯安裝mod_wsgi,注意指定python3的環境

發生錯誤:relocation R_X86_64_32S against `_Py_NotImplementedStruct' can not be used when making a shared object; recompile with -fPIC
/usr/python3.5/lib/libpython3.5m.a: error adding symbols: Bad value
collect2: error: ld returned 1 exit status
apxs:Error: Command failed with rc=65536
make: *** [src/server/mod_wsgi.la] Error 1
這個錯誤的解決辦法是要重新編譯python3的源碼,并加上--enable-shared選項
./configure --prefix=[python3的目錄] --enable-shared
可能重新編譯python后,運行python3的交互命令是,發生以下錯誤,依賴發生問題

通過復制python3目錄下lib/libpython3.5m.so.1.0到/lib64/libpython3.5m.so.1.0可以解決
此時,可以正常編譯mod_wsgi,且httpd/module/mod_wsgi.so依賴如下

注意: 重新編譯了python源碼,可能會造成擴展模塊的丟失,注意重新用pip安裝
python -m pip install [擴展模塊名稱]==[版本]
web界面顯示Not Found
Not Found
The requested URL / was not found on this server.

可能是django的項目路徑沒有配置對