项目驱动-两日速成Docker日记
经验总结写在前面:
有状态的功能模块,比如Mysql,要将数据文件挂载到宿主机
如果功能模块之间要通过 localhost 这种屏蔽具体 IP 的设置来通信的话,最好使用 --network=host 来让多个容器都共用一个NetworkSpace ,可以通过localhost互通
项目介绍:内部系统
需求环境:Tomcat + Mysql + Python
工作:前端选取 Excel 表格,传给后台 后台解析 Excel 表格,存入数据库,存入数据库后调用大数据组写好的 接口,通知Python服务器处理 Mysql 中的数据
业务都已经写好了,剩下 前端-后台-大数据 三方业务的联通
还没有联通测试,时间紧迫,懒得在本地搭环境测试,直接用Docker容器测试,反正到时候去内网部署也需要用 Docker 打包过去
一. 制作三者镜像
1.Tomcat
直接拉取tomcat:7-jre8, 我用的是 jdk8 写项目,tomcat用7比较稳,本地也是用7,怕出岔子。
接下去把自己的 war 包 放到 webapps 文件夹里就好了,前端本来想用 Nginx部署,但是只是一个演示程序,就把他一并交给Tomcat吧
放入 webapps :
sudo docker ps
查看到运行的 tomcat 容器的 ID 是 ABC(假设)
将文件夹放入 webapps, 可能不知道 这个文件夹的路径,这个路径是根据镜像来的,可以先进入容器看一下在哪
sudo docker exec -it ABC /bin/bash
上面这个指令就可以进入容器,因为要求容器运行 /bin/bash 并且 -it 要求分配一个 终端
一般情况下在 tomcat:XXX 中会进入到 /usr/local/tomcat , 这个是设置好的用户登录点
打一下 ls 指令
于是知道了webapps 的路径: /usr/local/tomcat/webapps
使用 cp 指令把 war 包和 前端文件夹复制过去
sudo docker cp /code/abc.war fb9f:/usr/local/tomcat/webapps
sudo docker cp /code/dist fb9f:/usr/local/tomcat/webapps
格式:sudo docker cp 带完整路径的本地文件 容器id:容器中的路径
这样就可以把两份东西都放到 webapps里,最好重启一下容器,让放入的文件生效。
sudo docker restart 容器id
到此,可以正常访问刚刚放进去的 war 包程序 和 前端静态文件
接着要提交这个容器,把他变成静态的镜像。
sudo docker commit 容器id 仓库名:标签
示例: sudo docker commit fb9f wlq/gdj:tomcat
这样就打包好一个镜像了,具体还可以 把 镜像 push 到远程仓库,和 git 一样,只不过git管理的是代码,docker 管理的是软件一层层的Layer,一个镜像是由许多层Layer组成的,在构建镜像的时候,没执行一次RUN 就会生成新的一层Layer。
2.Python 服务器
大数据组给我的是写好的Python程序,需要用命令行的形式运行 .py 文件,还是用Dockerfile 构建比较好。
Dockerfile 只要构建出 镜像,镜像就和这个Dockerfile 没有关系了,Dockerfile 只是描述要怎么构建镜像
需要python环境,而且版本要求3.6,于是从python:3.6上构建,先是创建一个文件夹,用来存放python服务器的文件,-p 表示递归创建
WORKDIR 改变当前工作目录,使得下方的 COPY 指令能在当前目录下找到 Project 这个文件夹,并且放到后面的 /usr/local/stgdj/py 文件夹里,注意,这些文件夹指的都是镜像中的文件夹,Dockerfile可以塑造
镜像,一层层镜像上运行容器,容器运行时可修改,镜像不行。
pip3 是安装库,最后用 python 指令运行 de.py
3.Mysql
相对于 前两者,Mysql 是有状态的模块,所谓有状态,就是用户的数据需要固定保存,如果机器重启,数据依然还在。
这就需要把 Mysql 容器的数据文件 挂载在宿主机
先把镜像构建好:Dockerfile:
FROM mysql:5.7
ENV MYSQL_ROOT_PASSWORD 123
COPY /code/abc.sql /mysql/abc.sql #将要导入的数据sql文件 COPY到镜像 COPY my.cnf /etc/mysql/my.cnf #自己写好的配置,放到my.cnf COPY到镜像
RUN chmod 000 /etc/mysql/my.cnf #把配置文件改下权限,如果是其他人可读写,Mysql会拒绝承认这个安全性低的配置文件 CMD ["mysqld", "--user=root"] #启动mysql,要把 --user=root 加上,不然的话,无法启动
其中的MYSQL_ROOT_PASSWORD是指定ROOT用户的密码,很贴心吧,Docker专门设置了这个环境变量
启动容器的时候,要加上挂载选项
sudo docker run -v 宿主机目录:容器目录 镜像id
sudo docker run -v /code/mysql:/var/lib/mysql abc
mysql的数据一般存在 /var/lib/mysql , 所以把这个文件夹挂载到宿主机的 /code/mysql 文件夹中,下一次启动容器,数据还在
接着要进去 容器,把刚才复制进去的 sql 文件导入到数据库
网络问题:一开始懵懵懂懂, 开了三个容器,三个容器里的配置的相互访问都是 访问localhost, tomcat 的 war 访问数据库是 localhost:3306, 访问py程序是 localhost:5000, py 服务器访问数据库也是 localhost:3306, 当时发现根本无法联通,后来学习到 docker 默认使用桥接模式,三个容器都会有自己独立的 Network Namespace,有自己的IP,端口等一系列网络组件。又不是同一套网络组件,当然无法
从localhost访问。
一开始用的是 --link 去连接 tomcat 和 mysql,py服务器和 mysql,但是后来发现 tomcat 还要连 py服务器,就束手无策了,因为 --link 只能连接两个容器
于是把 war 里指定访问IP的配置文件挂载出来放到 宿主机上,把访问 ip 设置成 docker0的 ip 或 宿主机局域网的 ip,但是这样还是不优雅
其实最终的解决方案是把容器的 网络模式变成 host 这样的话都共用 宿主机的一套网络组件
可以通过 localhost 相互通信
sudo docker run --net=host 镜像id
运行时常用命令
docker exec -it 容器id /bin/bash docker run -d -v dir:dir --net=hsot --expose port -- 镜像id docker cp dir 容器id:dir docker commit 运行中容器id 仓库名:标识符(镜像名)
Dockerfile常用 ENV 环境名 环境值 (设置环境) COPY 当前目录下(宿主机)文件名 容器中文件名 (拷贝文件) WORKDIR 目录名 (改变工作目录,工作目录在宿主机) RUN chmod 000 文件名 (RUN 命令,在镜像中生效,相当于在镜像上盖多一层,本语境相当于改变镜像中某个文件权限为000) CMD ["mysqld", "--user=root"] (让镜像跑成容器时 默认执行的命令,如果始用 docker run ... 命令(比如/bin/bash) ,则CMD会被覆盖)
ENTRYPOINT 在跑成容器时必然执行,不像CMD一样,可能被忽略