├── Dockerfile ├── README.md ├── docker-entrypoint.sh └── requirements.txt /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM daocloud.io/python:2.7 2 | MAINTAINER Captain Dao 3 | 4 | RUN mkdir -p /app 5 | WORKDIR /app 6 | 7 | ADD requirements.txt requirements.txt 8 | RUN pip install -r requirements.txt 9 | 10 | COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh 11 | RUN chmod +x /usr/local/bin/docker-entrypoint.sh 12 | 13 | EXPOSE 8888 14 | ENTRYPOINT ["docker-entrypoint.sh"] 15 | CMD [""] 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 如何开发一个基于 Docker 的 Python 应用 2 | 3 | > 目标:用 Docker 的方式搭建一个 IPython Notebook 应用 4 | > 5 | > 本项目代码维护在 **[DaoCloud/python-ipython-notebook](https://github.com/DaoCloud/python-ipython-notebook)** 项目中。 6 | > 7 | > 您可以在 GitHub 找到本项目并获取本文中所提到的所有代码文件。 8 | 9 | #### 前言 10 | 11 | Python 家族成员繁多,解决五花八门的业务需求。这里将通过 Python 明星项目 IPython Notebook,使其容器化,让大家掌握基础的 Docker 使用方法。 12 | 13 | > IPython Notebook 目前已经成为用 Python 做教学、计算、科研的一个重要工具。 14 | 15 | #### Docker 化应用的关键元素 16 | 17 | * 镜像是 Docker 应用的静态表示,是应用的交付件,镜像中包含了应用运行所需的所有依赖:包括应用代码、应用依赖库、应用运行时和操作系统。 18 | * Dockerfile 是一个描述文件,描述了产生 Docker 镜像的过程,详细文档可以参见官方文档 **[Dockerfile reference](https://docs.docker.com/reference/builder/)**。 19 | * 容器是镜像运行时的动态表示,如果把镜像想象为一个 Class 那么容器就是这个 Class 的一个实例。 20 | 21 | 一个应用 Docker 化的第一步就是通过 Dockerfile 产生应用镜像。 22 | 23 | #### 编写 Dockerfile 24 | 25 | * 选择 Python 2.7 版本为我们依赖的系统镜像。 26 | 27 | ```dockerfile 28 | FROM python:2.7 29 | ``` 30 | 31 | > 因所有官方镜像均位于境外服务器,为了确保所有示例能正常运行,可以使用与官方镜像保持同步的 DaoCloud 境内镜像:`FROM daocloud.io/python:2.7`。 32 | > 33 | > 也推荐通过 **[DaoCloud Toolbox](http://blog.daocloud.io/toolbox)** 极速下载官方镜像! 34 | 35 | * 设置镜像的维护者,相当于镜像的作者或发行方。 36 | 37 | ```dockerfile 38 | MAINTAINER Captain Dao 39 | ``` 40 | 41 | * 向镜像中添加文件并安装依赖。 42 | 43 | ```dockerfile 44 | RUN mkdir -p /app 45 | WORKDIR /app 46 | 47 | ADD requirements.txt requirements.txt 48 | RUN pip install -r requirements.txt 49 | 50 | COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh 51 | RUN chmod +x /usr/local/bin/docker-entrypoint.sh 52 | ``` 53 | 54 | > ##### `ADD` 与 `COPY` 的区别 55 | > 56 | > 总体来说 `ADD` 和 `COPY` 都是添加文件的操作,其中 `ADD` 比 `COPY` 功能更多,`ADD` 允许后面的参数为 URL,还有 `ADD` 添加的文件为压缩包的话,它将自动解压。 57 | > 58 | > ##### 使用 `RUN` 命令调用 pip 包管理器安装 App 的依赖包 59 | > 60 | > 在编写 Dockerfile 时尽量将安装依赖的过程提前以提高镜像层的复用率。 61 | > 62 | > ##### 设置 `docker-entrypoint.sh` 文件的执行权限 63 | > 64 | > 在 Dockerfile 中设置文件权限,可以保证其在每次制作完成的镜像里的权限都是正确的。 65 | 66 | * 启动应用进程 67 | 68 | ```dockerfile 69 | EXPOSE 8888 70 | ENTRYPOINT ["docker-entrypoint.sh"] 71 | CMD [""] 72 | ``` 73 | 74 | > 通过 `EXPOSE` 指定该镜像需要公开的端口。 75 | > 76 | > ##### `ENTRYPOINT` 与 `CMD` 的区别 77 | > 78 | > `ENTRYPOINT` 指定了该镜像启动时的入口,`CMD` 则指定了容器启动时的命令,当两者共用时,完整的启动命令像是 `ENTRYPOINT + CMD` 这样。使用 `ENTRYPOINT` 的好处是在我们启动镜像就像是启动了一个可执行程序,在 `CMD` 上仅需要指定参数;另外在我们需要自定义 `CMD` 时不容易出错。 79 | 80 | #### 制作启动脚本(docker-entrypoint.sh) 81 | 82 | ```bash 83 | #!/bin/bash 84 | # Strict mode 85 | set -euo pipefail 86 | 87 | # Create the hash to pass to the IPython notebook, but don't export it so it doesn't appear 88 | # as an environment variable within IPython kernels themselves 89 | HASH=$(python -c "from IPython.lib import passwd; print(passwd('${PASSWORD:-admin}'))") 90 | 91 | echo "========================================================================" 92 | echo "You can now connect to this Ipython Notebook server using, for example:" 93 | echo "" 94 | echo " docker run -d -p :8888 -e password= ipython/noetebook" 95 | echo "" 96 | echo " use password: ${PASSWORD:-admin} to login" 97 | echo "" 98 | echo "========================================================================" 99 | 100 | unset PASSWORD 101 | 102 | ipython notebook --no-browser --port 8888 --ip=* --NotebookApp.password="$HASH" 103 | ``` 104 | 105 | 一般我们会将初始化应用的过程编写成一个启动脚本,在脚本里以环境变量或命令行参数的形式获取应用初始化所必须的信息,然后配置并启动应用。 106 | 107 | #### 启动容器 108 | 109 | 有了 Dockerfile 以后,我们可以运行下面的命令构建 Python 应用镜像并命名为 `ipython/notebook`: 110 | 111 | * 通过指令建立镜像 112 | 113 | ``` 114 | docker build -t ipython/notebook . 115 | ``` 116 | 117 | * 通过以下指令启动容器 118 | 119 | ``` 120 | docker run -d -p 8888:8888 -e PASSWORD=admin ipython/notebook 121 | ``` 122 | 123 | 注意哦,我们将初始登录密码以环境变量的形式传入容器并告知应用。 124 | 125 | 打开游览器,访问 8888 端口,就可以看到 IPython Notebook 了。 126 | 127 | ![ipython login](http://blog.daocloud.io/wp-content/uploads/2015/09/QQ20150902-1.png) 128 | 129 | ![](http://blog.daocloud.io/wp-content/uploads/2015/09/QQ20150902-2.png) 130 | -------------------------------------------------------------------------------- /docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Strict mode 3 | set -euo pipefail 4 | 5 | 6 | # Create the hash to pass to the IPython notebook, but don't export it so it doesn't appear 7 | # as an environment variable within IPython kernels themselves 8 | HASH=$(python -c "from IPython.lib import passwd; print(passwd('${PASSWORD:-admin}'))") 9 | 10 | echo "========================================================================" 11 | echo "You can now connect to this Ipython Notebook server using, for example:" 12 | echo "" 13 | echo " docker run -d -p :8888 -e password= ipython/notebook" 14 | echo "" 15 | echo " use password: ${PASSWORD:-admin} to login" 16 | echo "" 17 | echo "========================================================================" 18 | 19 | unset PASSWORD 20 | 21 | ipython notebook --no-browser --port 8888 --ip=* --NotebookApp.password="$HASH" 22 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | ipython[all] 2 | --------------------------------------------------------------------------------