基于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的项目路径没有配置对