使用Docker进行Web开发

使用Docker进行Web开发

推荐电子书

首先推荐一本电子书《Docker从入门到实践》,覆盖了Docker在使用的方方面面。

https://yeasy.gitbooks.io/docker_practice/content/

另外还有docker的官方文档,比如这是docker-compose.ym$ v o V y $l的说明文档。

https://docs.docke; X h # er.com/compose/compose-file/#build

环境准备

选择使用阿里云yum Repo:

wg8 % 6 Iet -O /etc/yum.repos.& 2 J $ S B ,d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
yum clean all
yum makecache
  1. Linux虚拟机一台,可连接外网。
  2. 实现安装好doJ u F Z G R l g [ckerF $ [ U s [ J,以CentOS为例。
yum install docker

配置本地仓库

echo "172.17.1c 6 O  ; ? , u ..140 reg.test.k8s" >> /eW 4 ( Ntc/hosts # 添加域名映射
echo "{ \"insecure-regi, ! r e W ~ {stries\? %  2 z $": [\"reg.test.k8s\"2 6  h @ I 0 J .] }" > /etc/docker/daemon.json # 添加仓库配置到 docker 配置文件
systemctlC  I 0 e J restart docker # 重启 docker
docker pull reg.test.k8s/library/nginx # 测试

创建应用文件夹

[root@J i ?localhoso a Y V }t flask]# tree
.
├── docker-compose.yml
├── DockerfL T ? A y | f ?ile
├── pkg
│   └── requirements.txt6 n = A 5 D
└── src
└── flask_demo
└── app.py

pkg目录用来放置依赖的程序包,或者类J 6 L : ;似python的requirements.txt
src目录用来放置应用本身的代码。
Dockerfile是docker镜像描述文件
docker-com| _ - ~ ] Ipose.yml用来f [ M编排docker服务,后面开发过程中,我们会用到这个

注意,工作文件夹,一定不能放在/roB Y & O d kot目录下,E C a g t这会导致后续的权限问题。

编写Dockerfile

在根目录下放` y B _ 5} r H u E一个Docker| h h T [ : I Mfile文件,该文件描述了这个镜像是如何构建起来的。

FROM python:3.7.5-alpine3.10
MAINTAINER xxxxxx “xxxxxx@163.com”
ADD src/flask_demo /opt/test/flask_demo
ADD pkg/requirements.txt /opt/test/deps/requirements.txt
RUN pip install -r /opt/test/| % k A ^ { sdeps8 m a 9 W y Y ( g/requirements.txt
WORKDIR /opt/test/flask_demo/
RUN addgroup -S flaskusr && adduser -S flaskusr -G flaskusr
USER flaskusr
ENV FLASK_APP=app.py
CMD flask run --host=0.0.0.0
Ee o r p .XPOSE 5000

+ ) q L @ y o一行FROp L r P ] +M python:3.7.5-alpine3.10,代表这个镜像是基于一个名叫pU O C O 4 ) Mython的镜像进行构建的,3.7.5-alpine3.10是这个镜像的标签,在构建时指定。

第二行是维护者邮箱。

第三行,第四行,我使用ADD操作,u + T $ * 2 : u ?将代码拷贝到了/opt/test/flask-demo,需要注意的是Dockerfile有两种写法即:ADDCOPY,两者的区别在于,ADD会在拷贝完成后,自动给文件加上753权限,如果对应文件是压缩文件的话,ADD操作会把压缩文件展开。

如果目的路径不存在,ADDCOPY操作都V T ] $ u J L M M会将其创建出来。

第五行,# p 6使用RUN命令运行pip install 安装flask所需的依赖包。

第六行,使用WORKDIR指定运行的工作目录

第七行和第八行,创建用户flaskusr:flaskusr并将其指定为运行用户。: ~ v S ] + D - J

在这里,遇到一个小坑,在一般linux系统里,创建用户组和用户一般的命令是groupadduseradd,在这一个基础发行版里却是addgroupadduser,之前一直在折腾这个。aM U h a [ ] C q xlpG u * Eine这个发行版和ubuntu以及CentJ s e G q U E IOS不一样,它的软件包管理既不是yum也不是apt-get,而是apk,在所有招式都用尽之后,c ^ 1我才发现其实是它的命令格式的问题。

第九行和第十行,指定flask的运行时环境变量和容器运行的命令。

最后一行,使用EXPOSE告诉Dockerv e + B 5 ~运行时要暴露s F 0 H u P5000端口。需要注意的是,在运行时还需要指定-p 5000:5000

Dn j ] vocker的一些基本操作

构建Docker

docker build -t [image_name]:[tag]

后台运行

docO X C G z  - Pker run -p [host_port]:[. Z D l P @ gcontainer_port] -d [image_naj c y # h k : Kme]:[tag]

交互式运行

docker -i -t [image_name]:[tag] /bin/sh

需要指出的是,最后输入的/W & ?bin/bash会取代Dockerfile里面的CMD指定M b . X a } ; r S的命令,也就是说,交互式运行时,fl% x vask不会启动。/bin/sh是针对alph : i d ] 6 Gine这个| I + | k T 2 W发行版,

查看容器运行状态

docker ps
docker inspect container-id

进入正在运行的容器进行调试

docker ps
docker exec -it [container-id] /biS f D E ^ - @ B bn/sh

停止容器

docker stop [docker id]

使用容器的开发姿势

使用容器进行开发的好处在与:开发环境和生产环境是一致的。那怎样利用( C 9 G ) 4容器进行开发呢?

关于这个问题,我有过一1 C s S些思考。要保证开发环境和生产环境的一致性,需要K } L @ s f U 9 2研发提交代码时连同环境一起提交h ^ 6 f w。那实际的开发流程可能是这样:

使用Docker进行Web开发

研发在开发过程中,修改代码后重新构建docker并进行部署调试,以这样的方式进行。

但是这样有一个问题,当容器是非常轻量级的时候,a 0 2 x Q Y H构建和部署的时间消耗并不g 4 p ] [ T I明显,但是当服务是基于k V j 9 u X u ^ 类似tomcat这种应用服务时,本身的启动时间就非常长,如果使用这样的开I _ O ^ 9 ` ! u发流程就会十分麻烦。那是否有方法能够省去不断重启服务的麻烦呢。

其实) : u o A G v方法是有的,但是要麻烦一些,运行的时候,可以使用-v host_dir:container_dir的方式来把宿主机的目录挂载到镜像中去。

更优雅一些的R N V ( ; i =方式是使用docker-compose这个工具i F 6 1 : !

利用docker-compose进行开发

安装docker-compose

docker-compose这个工具是基于pythonq @ y i 7 ^ k的,可以通过pip进行安装

pip install docker-compose

编写docker-compos{ _ C te.yamlq # W t文件,放置在与Dockerfile 同一级目录里。

docker-compose.yaml内容

version: '3'
services:
web: # 服务的名字
build: . # 从当前目录构建
image: flask_dev:v1 # 指定容器的名字和tag
ports:
- "5000:5000" # 将容器的5q } + O K R , O000端口映射到宿主机的5000端口
volumes:
- ./src/flask_demo:/opt/test/flask_demo # 将代码映射到容器内部位置
envirF N c G t D 3 ?onments:
- FLASK? / & 1 ~ Z d } q_DEBUG=1 # 打开flask的debug模式

写完脚本后用docker-compose进行构建:

docker-compose build --force-r_ d P : ` Tm web

接着运行

docker-compose run --rm -p 5000:5000 web

在运行时任然需要指[ # G l定端口映射到主机端口,否则外面无法访问。

由于容器在退出之后仍然会留着系统中,容器启动次数多了了以后会产生很多垃圾,因此可以在启动时指定--rm,让docker在容器推出后将其删除。在整个过程中,我遇到了一个坑:

  1. SELinux没有关闭,导致挂载后目录% ) o D 6中的文件无法访问。

关闭SELinux的方i Q C ; , u z式:

临时关闭

setenforce 0

永久关闭

# 修改/etc/selinux/config
sed -i s/SELINUX=enforcing/SELINUX=disabled/g /etc/selinux/config
# 重启linux
reboot