docker-tutorial (2018-7-1)
This repo is a translation of the docs.docker.com.
Also, you can check the English version here.
2. Containers - 容器
You new development environment - 新的开发环境
如果你曾经写过Python, 你知道你首先要做的是在你的机器上安装Docker运行环境。设想一下这种情况,你有两个应用程序需要依赖一个相同的库,但是需要的版本不相同,这将会是一件非常糟糕的事情,而且实际开发的情况远比这要复杂。
使用Docker你可以把一个Python运行环境打包成一个镜像,然后你可在其中开发你的Python程序了,所有的库、依赖关系还有你的应用程序都是独立的不会被其他外界因素所影响。
Define a container with Dockerfile - 使用Dockerfile定义容器
Dockerfile
定义了你容器内部的环境和与外界交互的方式。当Dockerfile相同是,容器就是相同的。
Dockerfile
创建一个空目录,并且进入那个目录,创建一个文件名为Docekrfile
的文件,复制以下文本到其中。
# 使用一个官方的Python运行环境当做基本环境
FROM python:2.7-slim
# 设置工作目录为/app
WORKDIR /app
# 复制当前目录内容到容器中的/app目录
ADD . /app
# 安装requirements.txt文件中描述的所有需要的包
RUN pip install --trusted-host pypi.python.org -r requirements.txt
# 开放80端口给外部
EXPOSE 80
# 定义环境变量
ENV NAME Word
# 当容器启动时运行app.py
CMD ["python", "app.py"]
这个Dockerfile
以来一系列的文件,我们接下来创建他们。
The app itself - 应用程序
在同一个目录下创建requirements.txt
和app.py
两文件。当Docekrfile
构建镜像时,由于我们使用了定义了ADD
所以目录下的文件会被添加到镜像中。我们把80端口暴露到外界,所以可以通过80端口查看APP。
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=visits)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
Build the app - 构建应用程序
我们已经准备好构建应用程序了,确保你仍然在新建目录的顶层,ls
后应该显示如下内容:
$ ls
app.py Dockerfile requirements.txt
现在运行以下的命令来构建,这条命令会创建一个Docker镜像,我们可以使用-t
给他取一个名字:
$ docker build -t friendlyhello .
使用docker image ls
命令显示镜像列表:
$ docker image ls
REPOSITORY TAG IMAGE ID
friendlyhello latest a59873218b7e
python 2.7-slim 02ca219cf841
hello-world latest e38bc07ac18e
Run the app - 运行应用程序
运行程序,使用-p
参数把主机的4000端口映射到容器的80端口:
$ docker run -p 4000:80 friendlyhello
* Serving Flask app "app" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
Python应用程序在容器中http://0.0.0.0:80
提供了服务,我们把他映射到了主机的4000端口,所以可以通过http://localhost:4000
来获取他。
我们可以用curl
命令来访问这个应用程序提供的服务:
$ curl http://localhost:4000
<h3>Hello World!</h3><b>Hostname:</b> 49e76c9dd43a<br/><b>Visits:</b> <i>cannot connect to Redis, counter disabled</i>
好了,接下来关闭程序了,按下CRTL+C
就可以终止程序了。
由于这个程序是一个提供http服务的程序,所以我们可以让他在后台运行,可以使用-d
参数:
$ docker run -d -p 4000:80 friendlyhello
fbb2987bfa430b15a8616d0e77259b2f746c9005511607058c588010558f791c
你将会得到一个很长的APP ID,然后程序就在后台运行了,可以使用docker container ls
来查看容器和他们简短的容器ID:
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fbb2987bfa43 friendlyhello "python app.py" 2 minutes ago Up 2 minutes 0.0.0.0:4000->80/tcp gifted_nobel
现在可以用docker container stop
来终止这个容器,通过容器的ID来指定关闭的容器:
$ docker container stop fbb2987bfa43
fbb2987bfa43
Share your image - 分享你的镜像
Docker容器可以分发,就像Github上的仓库一样,我们可以去网上拉取别人或者是一些大公司已经建立的镜像,并且在他们的基础上构建我们自己的镜像,我们前面的例子就是这样的,当然我们也可以分享出我们自己的镜像来给别人使用。
Log in with you Docker ID - 用Docker ID登录
如果你还没有Docker账户,可以注册一个hub.docker.com.
登录Docker ID
$ docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username:
Password:
Login Succeeded
Tag the image - 为镜像起名
给镜像起名的格式是username/repository:tag
,tag
是可选的,但是推荐用tag来区分容器。
可以使用docker img image
来给镜像命名:
$ docker tag image username/repository:tag
例如:
$ docker tag friendlyhello chenjie3323/get-started:part2
然后,可以使用docker image ls
来查看刚刚打标签的镜像
$ docker iamge ls
REPOSITORY TAG IMAGE ID CREATED SIZE
chenjie3323/get-started part2 009af17a4c6a 25 minutes ago 132MB
friendlyhello latest 009af17a4c6a 25 minutes ago 132MB
<none> <none> a59873218b7e 30 minutes ago 132MB
python 2.7-slim 02ca219cf841 3 days ago 120MB
hello-world latest e38bc07ac18e 2 months ago 1.85kB
Publish the image - 发布镜像
上传你起好名的镜像:
$ docker push username/repository:tag
例如:
$ docker push chenjie3323/get-started:part2
The push refers to repository [docker.io/chenjie3323/get-started]
e383c98e1701: Pushed
0f7c4f3da142: Pushed
13cfd850c910: Pushed
7dd909bc1884: Mounted from library/python
13fd5e03bfb3: Mounted from library/python
28a70ee9f822: Mounted from library/python
9c46f426bcb7: Mounted from library/python
part2: digest: sha256:afeaef89398ffd676bf20cc200b1619405111ea071d869bc71eae271eff36c2b size: 1788
上传完成后,你的镜像就可以开放给其他人拉取了。如果登录到Docker hub你还能看到你的镜像。
Pull and run the image from the remote repository - 从远程仓库拉取和运行镜像
当使用docker run
命令运行镜像时,如果本地没有这个镜像,docker会自动的从网上拉取,并自动解决依赖的镜像。
命令速记
# 使用当前目录下的Dockerfile创建经镜像
$ docker build -t friendlyhello .
# 运行"friendlyname",把容器80映射到主机4000端口
$ docker run -p 4000:80 friendlyname
# 同上,但是以后台方式运行
$ docker run -d -p 4000:80 friendlyname
# 显示所有运行的容器
$ docker container ls
# 显示所有容器包括未运行的
$ docker container ls -a
# 关闭特定的容器
$ docker container stop <hash>
# 强制关闭特定容器
$ docker container kill <hash>
# 从本机中移除特定的容器
$ docker container rm <hash>
# 从本机中移除所有容器
$ docker container rm $(docker container ls -a -q)
# 显示本机中所有的镜像
$ docker image ls -a
# 移除特定的镜像
$ docker image rm <image id>
# 移除所有镜像
$ docker image rm $(docker image ls -a -q)
# 登录Docker hub账户
$ docker login
# 为上传的镜像打标签
$ docker tag <image> username/repository:tag
# 上传镜像
$ docker push username/repository:tag
# 运行远程镜像
$ docker run username/repo:tag