Docker入门
概念
- image 镜像,是一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,包括代码、运行的程序、库、环境变量和配置文件。
- container 容器是一个镜像运行时的实例 — 即镜像运行时在内存中变成的东西,默认情况下,它完全独立于主机环境运行,只在专门配置后才访问hosts file和端口。
每个容器都在独立进程中运行。
快速检查本机 docker
$ docker run hello-world
查看 docker 版本
$ docker -- version
容器
过往,当要写一个Python应用时,必须先安装Python环境,而且也会应用到你的主机环境上,同时对于运行你的应用的服务器也是这样,但是有了Docker以后,你不需要再安装Python,只需要抓取一个Python运行实例作为镜像,这样,你的构建活动就可以把Python镜像和你的代码一起工作了。
使用Dockerfile定义一个容器
Dockerfile会指明/决定在你的容器内环境中是如何配置运行的,
创建一个空文件夹,在里面创建一个名为Dockerfile的文件,写入以下内容
# Use an official Python runtime as a parent image
FROM python:2.7-slim
# Set the working directory to /app
WORKDIR /app
# Copy the current directory contents into the container at /app
ADD . /app
# Install any needed packages specified in requirements.txt
RUN pip install --trusted-host pypi.python.org -r requirements.txt
# Make port 80 available to the world outside this container
EXPOSE 80
# Define environment variable
ENV NAME World
# Run app.py when the container launches
CMD ["python", "app.py"]
新建两个文件 requirements.txt,app.py
requirements.txt
Flask
Redis
app.py
from flask import Flask
from redis import Redis, RedisError
import os
import socket
# Connect to Redis
redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)
app = Flask(__name__)
@app.route("/")
def hello():
try:
visits = redis.incr("counter")
except RedisError:
visits = "<i>cannot connect to Redis, counter disabled</i>"
html = "<h3>Hello {name}!</h3>"\
"<b>Hostname:</b> {hostname}<br/>"\
"<b>Visits:</b> {visits}"
return html.format(name=os.getenv('NAME',"world"), hostname=socket.gethostname(), visits=vistis)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
from flask import Flask
from redis import Redis, RedisError
import os
import socket
# Connect to Redis
redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)
app = Flask(__name__)
@app.route("/")
def hello():
try:
visits = redis.incr("counter")
except RedisError:
visits = "<i>cannot connect to Redis, counter disabled</i>"
html = "<h3>Hello {name}!</h3>"\
"<b>Hostname:</b> {hostname}<br/>"\
"<b>Visits:</b> {visits}"
return html.format(name=os.getenv('NAME',"world"), hostname=socket.gethostname(), visits=vistis)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
就是这样了,你的主机上不需要也不会安装 requirements.txt里的东西,看起来似乎你没有建立Python和Flask的运行环境,但实际上已经建立好了。
构建 app
# 文件目录如下
$ ls
Dockerfile app.py requirements.txt
运行构建命令
这会创建一个Docker镜像,我们将要使用标签 -t 让它有一个友好的名字
$ docker build -t friendlyhello .
建好的镜像在哪呢? 它在你本机的Docker镜像库中
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
friendlyhello latest 29dc95b5952a 2 hours ago 148MB
运行app
$ docker run -p 4000:80 friendlyhello
* Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
172.17.0.1 - - [18/Jan/2018 08:45:21] "GET / HTTP/1.1" 200 -
172.17.0.1 - - [18/Jan/2018 08:45:21] "GET /favicon.ico HTTP/1.1" 404 -
172.17.0.1 - - [18/Jan/2018 08:46:00] "GET / HTTP/1.1" 200 -
打开浏览器进入 http://localhost:4000 可以看到结果
你也可以使用 curl 命令在命令行环境下看到相同的结果
$ curl http://localhost:4000
<h3>Hello World!</h3><b>Hostname:</b> 8fc990912a14<br/><b>Visits:</b> <i>cannot connect to Redis, counter disabled</i>
以分离模式 后台运行app
$ docker run -d -p 4000:80 friendlyhelloworld
查看容器进程
现在容器在后台运行,你可以使用 docker container ls
命令查看压缩后的容器ID
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6bde28605607 friendlyhello "python app.py" 2 minutes ago Up 2 minutes 0.0.0.0:4000->80/tcp zealous_heyrovsky
结束进程
使用 docker container stop
命令来结束进程,CONTAINER ID作参数
$ docker container stop 6bde28605607
共享你的镜像
一个 registry 是很多 repositories 的集合,一个 repositories 是许多 image 的集合 — 就像GiHub的仓库,默认情况下,docker CLI 使用 Docker 的公用 registry
用你的Docker ID登录
# 从你的本地主机登录到Docker公用registry
$ docker login
给镜像添加标签
将一个本地镜像和一个registry上的repository相关联的方法是 username/repository:tag
,tag是可选的,但是推荐使用,因为它是registries用来给Docker镜像赋予版本号的机制。
$ docker tag image username/repository:tag
示例:
$ docker tag friendlyhello huangke19/get-started:part2
发布镜像
$ docker push username/repository:tag
一旦完成,这次上传的结果就可以公开访问了,如果你登入Docker Hub,你将会看到你的新镜像(和它的pull命令)
从远端仓库拉取和运行镜像
$ docker run -p 4000:80 username/repository:tag
如果镜像不在本地,Docker会把它拉下来并运行
$ docker run -p 4000:80 john/get-started:part2
Unable to find image 'john/get-started:part2' locally
part2: Pulling from john/get-started
10a267c67f42: Already exists
f68a39a6a5e4: Already exists
9beaffc0cf19: Already exists
3c1fe835fb6b: Already exists
4c9f1fa8fcb8: Already exists
ee7d8f576a14: Already exists
fbccdcced46e: Already exists
Digest: sha256:0601c866aab2adcc6498200efd0f754037e909e5fd42069adeff72d1e2439068
Status: Downloaded newer image for john/get-started:part2
* Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
不管在哪里运行 docker run
, 它都会拉取你的镜像,其中包含 Python
和 requirements.txt
里的所有依赖,然后运行代码 ,它们总是作为一个整齐干净的小包裹移动,而主机环境除了Docker完全不需要安装任何东西。