Docker是开发人员和系统管理员使用容器构建、运行和共享应用程序的平台。Docker促进了应用程序的可移植性和可伸缩性。Docker提供了应用程序隔离,从而消除了库和环境差异引起的许多问题。它有助于自动化开发和部署。使用预定义的社区镜像(image),开发人员可以节省时间并改善他们的整体体验。
Docker镜像(image)是一个只读模板,包含创建Docker容器的说明。Docker容器是一个镜像的可运行实例。
Docker镜像存储在存储库中。Docker Hub是官方的Docker存储库。Docker引擎是底层的客户机-服务器技术,它使用Docker的组件和服务构建和运行容器。
Dockerfile
是一个特殊的文件,它包含了构建Docker镜像所需的指令。
$ sudo docker --version
Docker version 19.03.12, build 48a66213fe
这是我们使用的Docker版本。
在下面的示例中,我们创建并运行一个非常简单的Docker镜像。当我们运行这个镜像时,会执行一个简单的Python文件。
hello.py
#!/usr/bin/python
import sys
print("hello there!")
print(sys.version)
这是要在容器内执行的简单文件。
Dockerfile
FROM python:3.8
COPY hello.py /tmp/
CMD ["python", "/tmp/hello.py"]
这些是构建Docker镜像的指令。
FROM python:3.8
我们的镜像文件基于社区python:3.8
镜像。
COPY hello.py /tmp/
COPY
指令将hello.py
文件复制到镜像的tmp
目录中。
CMD ["python", "/tmp/hello.py"]
CMD
指令启动Python程序。
$ sudo docker build -t hello .
我们用docker build
命令构建新的名为hello
的镜像文件。
$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello latest 60251c18f538 5 minutes ago 882MB
firstimage latest 319917db1025 5 hours ago 111MB
python slim 38cd21c9e1a8 5 days ago 113MB
python 3.8 79cc46abd78d 5 days ago 882MB
python latest 79cc46abd78d 5 days ago 882MB
我们使用docker images
命令列出可用的镜像。
$ sudo docker run hello
hello there!
3.8.5 (default, Aug 5 2020, 08:22:02)
[GCC 8.3.0]
我们用docker run
运行hello
镜像。
我们可以使用-it
选项以交互模式运行镜像。它指示Docker分配一个连接到容器stdin的伪TTY终端;在容器中创建交互式bash shell。
$ sudo docker run -it python3.8:slim bash
root@98ece0c01946:/#
我们运行镜像并在容器中获取bash shell。
root@98ece0c01946:/# python -c "import os; print(os.system('ls -l'))"
total 68
drwxr-xr-x 1 root root 4096 Aug 4 16:25 bin
drwxr-xr-x 2 root root 4096 Jul 10 21:04 boot
drwxr-xr-x 5 root root 360 Aug 19 13:40 dev
drwxr-xr-x 1 root root 4096 Aug 19 13:39 etc
drwxr-xr-x 2 root root 4096 Jul 10 21:04 home
drwxr-xr-x 1 root root 4096 Aug 4 16:25 lib
drwxr-xr-x 2 root root 4096 Aug 3 07:00 lib64
drwxr-xr-x 2 root root 4096 Aug 3 07:00 media
drwxr-xr-x 2 root root 4096 Aug 3 07:00 mnt
drwxr-xr-x 2 root root 4096 Aug 3 07:00 opt
dr-xr-xr-x 345 root root 0 Aug 19 13:40 proc
drwx------ 1 root root 4096 Aug 4 16:18 root
drwxr-xr-x 3 root root 4096 Aug 3 07:00 run
drwxr-xr-x 2 root root 4096 Aug 3 07:00 sbin
drwxr-xr-x 2 root root 4096 Aug 3 07:00 srv
dr-xr-xr-x 13 root root 0 Aug 19 13:40 sys
drwxrwxrwt 1 root root 4096 Aug 11 20:37 tmp
drwxr-xr-x 1 root root 4096 Aug 3 07:00 usr
drwxr-xr-x 1 root root 4096 Aug 3 07:00 var
0
我们可以运行Python代码。
root@98ece0c01946:/# python -c "import sys; print(sys.version)"
3.8.5 (default, Aug 4 2020, 16:24:08)
[GCC 8.3.0]
在我们的例子中,我们预装了Python 3.8.5。
在下一个示例中,我们构建一个检索HTML页面的镜像。我们使用请求库,它必须安装在镜像中。
get_req.py
#!/usr/bin/python
import requests as req
resp = req.get("http://webcode.me")
print(resp.text)
代码示例通过发出GET请求来重试一个简单的web页面。
Dockerfile
FROM python:slim
RUN pip install requests
COPY get_req.py /tmp/
CMD ["python", "/tmp/get_req.py"]
这是Dockerfile。
FROM python:slim
在本例中,我们使用社区python:slim
镜像,它占用的空间少得多(slim有苗条的意思)。
RUN pip install requests
使用RUN
指令,我们执行pip管理器并安装请求模块。
COPY get_req.py /tmp/
COPY
指令将get_req.py
文件从主机复制到容器的/tmp/
目录。如果目录不存在,则创建该目录。
CMD ["python", "/tmp/get_req.py"]
CMD
指令在启动容器时运行程序。
$ sudo docker build -t pygetreq .
我们构建镜像并将其命名为pygetreq
。
$ sudo docker images | grep pygetreq
pygetreq latest 0d3c5953ff60 23 seconds ago 121MB
这个镜像只需要121MB。
$ sudo docker run pygetreq
My html page
Today is a beautiful day. We go swimming and fishing.
Hello there. How are you?
在下一个示例中,我们将在Docker容器中运行一个简单的Flask应用程序。
app.py
#!/usr/bin/python
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello there!'
这是一个简单的Flask应用程序,只有一个主路由。
Dockerfile
FROM python:slim
COPY app.py /app/
WORKDIR /app
RUN pip install flask
RUN export FLASK_APP=app.py
EXPOSE 5000
CMD ["/usr/local/bin/flask", "run", "--host", "0.0.0.0"]
这是Dockerfile。
FROM python:slim
我们将我们的镜像建立在python:slim
的image上。
COPY app.py /app/
WORKDIR /app
我们将一个文件复制到镜像上的一个目录,并设置工作目录。如果目录不存在,则创建该目录。
RUN pip install flask
使用RUN
指令,我们安装Flask。
RUN export FLASK_APP=app.py
将FLASK_APP
环境变量设置为app.py
文件。
EXPOSE 5000
我们暴露端口。
CMD ["/usr/local/bin/flask", "run", "--host", "0.0.0.0"]
使用CMD
指令,我们设置了容器启动时运行的默认命令。我们将主机IP设置为0.0.0.0
,以便应用程序可以在容器外部访问。
$ sudo docker build -t flasksimple .
我们构建image 文件。
$ docker run -p 5000:5000 flasksimple
我们运行image文件。容器的5000端口映射到主机的5000端口。
$ curl localhost:5000/
Hello there!
使用curl
工具,我们生成一个到应用程序的GET请求。
在下面的示例中,我们基于mariadb镜像创建一个容器。
schema.sql
USE testdb;
DROP TABLE IF EXISTS cities;
CREATE TABLE cities(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255), population INT);
INSERT INTO cities(name, population) VALUES('Bratislava', 432000);
INSERT INTO cities(name, population) VALUES('Budapest', 1759000);
INSERT INTO cities(name, population) VALUES('Prague', 1280000);
INSERT INTO cities(name, population) VALUES('Warsaw', 1748000);
INSERT INTO cities(name, population) VALUES('Los Angeles', 3971000);
INSERT INTO cities(name, population) VALUES('New York', 8550000);
INSERT INTO cities(name, population) VALUES('Edinburgh', 464000);
INSERT INTO cities(name, population) VALUES('Berlin', 3671000);
这是cities
表的SQL代码。
Dockerfile
FROM mariadb
RUN apt-get update && apt-get install -y \
python3.8 \
python3-pip
RUN pip3 install pymysql
ADD schema.sql /docker-entrypoint-initdb.d
ENV MYSQL_USER=user7
ENV MYSQL_PASSWORD=7user
ENV MYSQL_DATABASE=testdb
ENV MYSQL_ROOT_PASSWORD=s$cret
EXPOSE 3306
我们从mariadb
image得到新的镜像。
RUN apt-get update && apt-get install -y \
python3.8 \
python3-pip
在镜像上,我们安装Python和pip
。
RUN pip3 install pymysql
我们安装pymysql
驱动程序。
ADD schema.sql /docker-entrypoint-initdb.d
/docker-entrypoint-initdb.d
目录下的SQL脚本在容器初始化时运行。我们使用ADD
指令复制模式文件。
ENV MYSQL_USER=user7
ENV MYSQL_PASSWORD=7user
ENV MYSQL_DATABASE=testdb
ENV MYSQL_ROOT_PASSWORD=s$cret
使用环境变量,我们创建一个新用户、一个新数据库,并为root用户设置一个密码。
EXPOSE 3306
EXPOSE
指令通知Docker容器在运行时监听指定的网络端口。
app.py
#!/usr/bin/python
import pymysql
con = pymysql.connect(host='localhost', user='user7',
password='7user', database='testdb', port=3306)
try:
with con.cursor() as cur:
cur.execute('SELECT * FROM cities')
rows = cur.fetchall()
for row in rows:
print(f'{row[0]}, {row[1]}, {row[2]}')
finally:
con.close()
该示例连接到在容器内运行的MariaDB testdb
数据库。它显示cities
表中的所有行。
$ sudo docker build -t pymaria-simple .
Sending build context to Docker daemon 4.608kB
Step 1/9 : FROM mariadb
---> b95867b52886
Step 2/9 : RUN apt-get update && apt-get install -y python3.8 python3-pip
---> Using cache
---> 9370769248ed
Step 3/9 : RUN pip3 install pymysql
---> Using cache
---> 108146aaa2d8
...
我们构建镜像文件。
$ sudo docker run -p 3306:3306 pymaria-simple
我们从定制的pymaria-simple
镜像运行容器。使用-p
选项,我们将容器的3306
端口发布到主机端口3306
。
$ ./app.py
1, Bratislava, 432000
2, Budapest, 1759000
3, Prague, 1280000
4, Warsaw, 1748000
5, Los Angeles, 3971000
6, New York, 8550000
7, Edinburgh, 464000
8, Berlin, 3671000
容器启动后,我们运行app.py
程序,该程序将显示城市。
在本教程中,我们使用了Python和Docker。