百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

Docker入门教程(2)容器

toyiye 2024-06-21 12:32 11 浏览 0 评论

前提条件

docker run hello-world

简介

现在,我们会以Docker的方式来构建应用程序。首先,我们会从这种容器化的应用程序的最底层开始学习,本文将会涵盖容器(Container)的相关知识。其次,容器的更上一层是服务(Service),它能够定义容器在生产环境中的具体行为,本系列教程的第三部分将会涵盖服务的相关知识。最后,最顶层是堆栈(Stack),它能够定义所有服务之间的交互作用,本系列教程的第五部分将会涵盖堆栈的相关知识。

  • 堆栈

  • 服务

  • 容器(本文涵盖内容)

你的新开发环境

在过去,如果你想要开始编写一个Python应用程序,那么你首先应当为你的计算机安装一个Python运行时环境。但是,这样便会存在一种情况,只有你的计算机环境才能使得你的应用程序能够按照预期运行,因此运行这个应用程序的服务器也必须按照你的计算机环境进行配置。

通过Docker,你可以只抓取一个可移植的Python运行时镜像,而不需要为主机安装Python运行时环境。然后,你构建的应用程序不仅包含你的程序代码,还会包含基础的Python镜像,这样便能确保你的应用程序、依赖关系和运行时环境能够整体部署和迁移。

这些可移植的镜像是由一些被称为Dockerfile的配置文件所定义的。

通过Dockerfile定义容器

Dockerfile文件将会定义你的容器内部环境的方方面面。在容器环境中,对诸如网络接口和磁盘驱动器之类资源的访问都是虚拟化的,这样便能将容器和宿主机系统完全隔离。因此,你必须将容器的端口映射至外部网络,并且需要指定将哪些文件拷贝至容器环境之中。然而,在这样做之后,你就可以确保在Dockerfile文件中定义和构建的应用程序能够在任何环境中保持相同的行为。

创建一个空目录,然后将以下文件放置在该目录之中,文件名为Dockerfile。请仔细阅读解释每条语句的注释。

Dockerfile文件:

# 使用官方的Python运行时镜像作为父镜像
FROM python:2.7-slim

# 将工作目录设置为/app
WORKDIR /app

# 将当前目录的内容拷贝至容器的/app目录
ADD . /app

# 安装requirements.txt文件中指定的软件包
RUN pip install -r requirements.txt

# 向外界开放容器的80端口
EXPOSE 80

# 定义环境变量
ENV NAME World

# 当容器启动时,运行app.py
CMD ["python", "app.py"]

这个Dockerfile会引用两个文件,名为app.py和requirements.txt,现在尚未创建这两个文件。接下来,我们便会创建这两个文件。

应用程序本身

创建以下两个文件,然后将它们放置在存放Dockerfile的文件夹之中。这样便能完成我们的应用程序,你会发现这个应用程序非常简单。当根据上述的Dockerfile文件构建镜像时,Dockerfile的ADD命令会将app.py和requirements.txt文件添加至镜像,并且EXPOSE命令会使得通过HTTP访问app.py文件时,容器还会输出相应的信息。

requirements.txt文件:

Flask
Redis

app.py文件:

from flask import Flask
from redis import Redis, RedisError
import os
import socket

# Connect to Redisredis = 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)

由上述文件的内容可知,“pip install -r requirements.txt”命令会安装Python的Flask和Redis程序库,应用程序会输出环境变量NAME的值,除此之外还会输出调用“socket.gethostname()”的结果。最后,因为Redis并没有运行(我们只安装了Python程序库,并没有安装Redis缓存),我们应当可以预见,当应用程序试图使用缓存时,便会产生出错消息。

注意:当在一个容器内部访问主机名时,便会获取容器的标识符,类似于运行一个可执行程序时获得的进程标识符。

构建应用程序

就是这样!你的宿主机系统不需要安装Python或requirements.txt中的任何组件,构建或运行这个Docker镜像时也不会将上述组件安装至你的宿主机系统。虽然看起来你并没有建立Python和Flask的运行环境,但实际上你的宿主机系统已经具备运行条件了。

ls命令的输出,应当如下图所示:

现在,我们可以运行构建命令。这个命令会创建一个Docker镜像,我们会使用“-t”选项创建镜像的标签,这样便能为镜像指定一个较为友好的名称:

docker build -t friendlyhello .

若镜像构建成功,则命令输出如下图所示:

你构建的镜像存放在哪儿呢?它会存放在宿主机的本地Docker镜像仓库之中,如下图所示:

运行应用程序

运行应用程序,通过“-p”选项将宿主机的4000端口映射至容器的80端口,这个端口是由Dockerfile中的EXPOSE命令指定对外公开的:

docker run -p 4000:80 friendlyhello

你应该能够看到一条通知信息,提示Python正在通过http://0.0.0.0:80为你的应用程序提供服务。但是,这条消息是从容器内部发出的,由于你已经将容器的80端口映射至宿主机的4000端口,因此正确的访问URL应该是http://localhost:4000。

通过浏览器访问上述的URL,网页中显示的内容包括“Hello World”文本、容器标识符和Redis出错消息,如下图所示:

你还可以在Shell中运行curl命令,可以看到相同的内容:

注意:此处的4000:80端口映射可以说明通过Dockerfile文件中的EXPOSE命令公开端口和通过“docker run -p”命令发布端口映射之间的不同之处。在稍后的步骤中,我们会将宿主机的80端口映射至容器的80端口,通过http://localhost访问应用程序。

在终端中按下“CTRL+C”组合键,退出正在运行的容器。

现在,我们会在后台以分离模式运行应用程序的容器:

docker run -d -p 4000:80 friendlyhello

你会看到一串很长的容器标识符,然后便会返回至终端的命令提示符。此时,你的容器正在后台运行。你还可以通过“docker ps”命令查看缩短的容器标识符(当运行命令时,既可以使用缩短的容器标识符,也可以使用完整的容器标识符),如下图所示:

你会发现CONTAINER ID列的值和http://localhost:4000页面显示的值是相同的。

现在,使用“docker stop”命令就可以结束容器的进程,需要指定CONTAINER ID列的值,如下所示:

docker stop 829a0f568391

共享你的镜像

为了演示我们刚刚创建的容器镜像的可移植性,我们会上传构建得到的容器镜像,然后在其他地方运行相应的容器。最后,当你想要将容器部署至生产环境时,你还需要学习如何将容器镜像推送至镜像仓库。

镜像仓库是多个镜像存储库的集合,而镜像存储库又是多个镜像的集合 —— 类似于GitHub的存储库,但是镜像存储库的代码是已经构建完成的。镜像仓库的注册账号可以创建很多镜像存储库。docker命令行工具默认会使用Docker的公开镜像仓库。

注意:此处,我们将使用Docker的公开镜像仓库,因为它是免费和预配置的,但是你还可以选择很多其他的公开镜像仓库,你甚至还可以通过Docker可信镜像仓库搭建你自己的私有镜像仓库。

登录Docker账号

如果你没有Docker账号,那么可以在cloud.docker.com网站注册一个账号。请务必记住你的用户名!

在你的本地主机中登录至Docker的公开镜像仓库:

docker login

创建镜像标签

Docker镜像的名称是由仓库名称、存储库名称和标签构成的,格式为“username/repository:tag”。虽然标签(tag)是可选的,但是我们推荐使用标签,因为镜像仓库会通过标签来管理Docker镜像的版本。存储库名称和标签最好具有实际含义,例如:“get-started:part1”。镜像仓库会将上述镜像放置在“get-started”存储库之中,并且为其创建名为“part1”的标签。

现在,可以将所有组成部分拼接起来,然后为镜像创建标签。运行“docker tag image”命令,指定你的用户名、存储库和标签,这样便能将镜像上传至预想的位置。命令的语法如下所示:

docker tag image username/repository:tag

例如:

docker tag friendlyhello ghoulich/get-started:part1

运行“docker images”命令,查看最新创建的镜像标签(你也可以运行“docker image ls”命令),如下图所示:

发布镜像

将已经创建标签的镜像上传至镜像存储库,命令的语法如下所示:

docker push username/repository:tag

例如:

docker push ghoulich/get-started:part1

一旦镜像上传完成,那么这个镜像对外就是公开可用的。如果你登录Docker Hub网站,你将能看到先前上传的容器镜像,以及用来拉取这个镜像的命令。如下图所示:

从远程存储库拉取和运行镜像

从现在开始,你可以在任何一台主机中运行“docker run”命令,这样便能运行你的应用程序容器,命令的语法如下所示:

docker run -p 4000:80 username/repository:tag

例如:

docker run -p 4000:80 ghoulich/get-started:part1

如果宿主机本地没有找到这个容器镜像,那么Docker将会从镜像存储库拉取这个容器镜像,如下图所示:

注意:如果你在构建镜像或者运行容器时,没有在这些命令中指定镜像名称的“:tag”部分,那么默认会使用“:latest”标签。如果运行容器时没有指定标签,那么Docker将会使用最新版本的容器镜像。

无论在何处执行“docker run”命令,Docker都会拉取你的镜像(这个镜像包含Python运行环境,以及requirements.txt文件指定的所有依赖关系),然后运行容器中的app.py代码。应用程序的运行环境和依赖关系都被封装至容器镜像之中,宿主机只需要安装用于运行容器的Docker软件包,不需要安装其他任何东西。

结论

本节内容到此结束。在下一节之中,我们将学习如何以服务的方式运行容器,这样便能很方便地调整应用程序的规模。

回顾和备忘

以下列表包含本节涉及的基本Docker命令,以及进入下一节学习之前需要了解的一些命令:

docker build -t friendlyname . # 通过当前目录的Dockerfile创建镜像
docker run -p 4000:80 friendlyname # 运行“friendlyname”镜像,将4000端口映射至80端口
docker run -d -p 4000:80 friendlyname # 运行“friendlyname”镜像,以分离模式工作
docker ps # 查看所有正在运行的容器列表
docker stop <hash> # 停止运行指定的容器
docker ps -a # 查看所有容器列表,包括尚未运行的容器
docker kill <hash> # 强制停止运行指定的容器
docker rm <hash> # 从宿主机删除指定的容器
docker rm $(docker ps -a -q) # 从宿主机删除所有的容器
docker images -a # 显示宿主机所有的镜像
docker rmi <imagename> # 从宿主机删除指定的镜像
docker rmi $(docker images -q) # 从宿主机删除所有的镜像
docker login # 通过你的Docker账号登录CLI会话
docker tag <image> username/repository:tag # 为<image>指定的镜像创建标签
docker push username/repository:tag # 将已创建标签的镜像上传至镜像仓库
docker run username/repository:tag # 从镜像仓库拉取和运行镜像

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码