Docker学习4-Containers - 容器
用Docker方式构建应用程序,从这个应用程序层次结构的底层容器开始。高于此级别的是一项服务,它定义了容器在生产中的行为方式。在顶层是堆栈,它定义了所有服务的交互。
- Stack 堆栈
- Services 服务
- Container 容器
如果想用Python开发一个应用程序,必须先在机器上安装一个Python运行环境,计算机上的环境非常适合想要开发的应用程序,这样应用程序才能按预期运行,并且还需要与生产环境相匹配。若使用Docker,可以将可移植的Python运行时攫取作为一个镜像,而无需安装。构建过程包含了应用程序代码和基本的Python镜像,确保应用程序、其依赖项和运行时能够同时运行。这些可移植镜像定义在一个称为Dockerfile的文件中。Dockerfile用来创建一个自定义的镜像 image或定制镜像 image,包含了用户指定的软件依赖等。当前目录下包含Dockerfile文件,使用命令 build来创建新的镜像 image,并命名为edwardsbean/centos6-jdk1.7:
docker build -t edwardsbean/centos6-jdk1.7 .
使用 Dockerfile 定制镜像
镜像的定制实际上就是定制每一层所添加的配置、文件。如果可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决,这个脚本就是 Dockerfile。Dockerfile 是一个文本文件,其内包含了一条条的指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
Dockerfile关键字
FROM:
指定基础镜像,基于哪个镜像
所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。而 FROM 就是指定基础镜像,因此一个 Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令。除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 scratch 。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。如果以 scratch 为基础镜像的话,意味着不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。
RUN:
执行命令,安装软件用,RUN
指令是用来执行命令行命令的。
MAINTAINER:
镜像创建者
CMD:
container启动时执行的命令,一个Dockerfile中只能有一条CMD命令,多条则只执行最后一条CMD。CMD主要用于container时启动指定的服务,当docker run command的命令匹配到CMD command时,会替换CMD执行的命令。
ENTRYPOINT:
入口点,container启动时执行的命令,一个Dockerfile中只能有一条ENTRYPOINT命令,如果多条,则只执行最后一条。
USER:
指定当前用户,使用哪个用户跑container。
EXPOSE:
声明端口,container内部服务开启的端口。EXPOSE
指令是声明运行时容器提供服务端口,只是一个声明,在运行时并不会因为这个声明应用就会开启这个端口的服务。
ENV:
用来设置环境变量
格式:
- ENV <key> <value>
- ENV <key1>=<value1> <key2>=<value2>...
COPY:
复制文件
格式:
- COPY <源路径>... <目标路径>
- COPY ["<源路径1>",... "<目标路径>"]
ADD:
将文件<src>拷贝到container的文件系统对应的路径<dest>;
所有拷贝到container中的文件和文件夹权限为0755,uid和gid为0;
如果文件是可识别的压缩格式,则docker会帮忙解压缩;
如果要ADD本地文件,则本地文件必须在 docker build <PATH>,指定的<PATH>目录下;
如果要ADD远程文件,则远程文件必须在 docker build <PATH>,指定的<PATH>目录下。比如: docker build github.com/creack/docker-firefox,docker-firefox目录下必须有Dockerfile和要ADD的文件。ADD只有在build镜像的时候运行一次,后面运行container的时候不会再重新加载了。
VOLUME:
可以将本地文件夹或者其他container的文件夹挂载到container中。
WORKDIR:
指定工作目录(或者称为当前目录),切换目录用,可以多次切换(相当于cd命令),对RUN,CMD,ENTRYPOINT生效。
ONBUILD:
ONBUILD指定的命令在构建镜像时并不执行,而在它的子镜像中执行。ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN , COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。
Docker 组件与元素
Docker有三个组件和三个基本元素,三个组件分别是:
Docker Client
是用户界面,它支持用户与Docker Daemon之间通信。Docker Daemon
运行于主机上,处理服务请求。Docker Index
是中央registry,支持拥有公有与私有访问权限的Docker容器镜像的备份。
三个基本要素分别是:
Docker Containers
负责应用程序的运行,包括操作系统、用户添加的文件以及元数据。Docker Images
是一个只读模板,用来运行Docker容器。DockerFile
是文件指令集,用来说明如何自动创建Docker镜像。
运行任何应用程序,都需要有两个基本步骤:
·
构建一个镜像;
·
运行容器。
这些步骤都是从Docker Client
的命令开始的。Docker Client
使用的是Docker二进制文件。在基础层面上,Docker Client
会告诉Docker Daemon
需要创建的镜像以及需要在容器内运行的命令。当Daemon
接收到创建镜像的信号后,会进行如下操作:
第1步:构建镜像
如前所述,Docker Image
是一个构建容器的只读模板
,它包含了容器启动所需的所有信息,包括运行程序和配置数据等。每个镜像都源于一个基本的镜像,然后根据Dockerfile
中的指令创建模板。对于每个指令,在镜像上创建一个新的层面。一旦镜像创建完成,就可以将它们推送到中央
registry
:Docker Index
,以供他人使用。然而,Docker Index
为镜像提供了两个级别的访问权限:公有访问和私有访问。可以将镜像存储在私有仓库,Docker官网有私有仓库的套餐可以供你选择。总之,公有仓库是可搜索和可重复使用的,而私有仓库只能给那些拥有访问权限的成员使用。Docker Client
可用于Docker Index
内的镜像搜索。
第2步:运行容器
运行容器源于之前在第一步中创建的镜像。当容器被启动后,一个读写层会被添加到镜像的顶层。当分配到合适的网络和IP地址后,需要的应用程序就可以在容器中运行了。
Dockerfile定义一个容器
Dockerfile定义容器内环境中发生的一切事情。在环境中利用虚拟化技术对网络接口和磁盘驱动器等资源的访问进行了虚拟化,该环境与系统的其他部分隔离,因此需要将端口映射到外部,并明确要“拷贝进”什么文件到环境。执行此操作后,通过Dockerfile文件中定义的应用程序,无论在哪儿运行,应用程序的构建行为完全相同。
Dockerfile
建立一个空的目录,并进入该目录,创建一个名为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
COPY . /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"]
Dockerfile文件中包含了一些暂时还没有创建的文件,即app.py和requirements.txt文件。手动创建这些文件。当上述Dockerfile内置于镜像中时,由于Dockerfile中的COPY命令,app.py和requirements.txt文件同样存在,并且由于EXPOSE命令,app.py的输出可通过HTTP访问。
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)
可以看到pip install -r requirements.txt为Python安装了Flask和Redis库,应用程序打印环境变量NAME,以及调用socket.gethostname()的输出,Redis没有运行(因为只安装了Python库,而不是Redis本身)。
注意:在容器内部访问容器ID时,请访问主机名称,类似于正在运行的可执行文件的进程ID。
系统不需要Python或requirements.txt中的任何内容,构建或运行此镜像也不需要在系统上安装它们。看起来并没有真正建立一个Python和Flask的环境,但是实际上已经具有了环境。
Build the app
运行build命令。创docker建一个Docker镜像,使用 -t 标记:
[jeshy@master DockerStudy]$ sudo docker build -t friendlyhello .
构建的镜像位于机器的本地Docker镜像注册表中:
[jeshy@master DockerStudy]$ sudo docker image ls
Run the app
运行应用程序,使用-p将计算机的端口4000映射到容器的已发布端口80:
[jeshy@master DockerStudy]$ sudo docker run -p 4000:80 friendlyhello
通过浏览器打开URL http://localhost:4000
注意:如果在Windows 7上使用Docker Toolbox,请使用Docker Machine IP而不是localhost。 如,http://192.168.99.100:4000/。 要查找IP地址,请使用命令docker-machine ip。
还可以在shell中使用curl命令来查看相同的内容:
$ curl http://localhost:4000
以分离模式在后台运行应用程序:
sudo docker run -d -p 4000:80 friendlyhello
[jeshy@master DockerStudy]$ sudo docker run -d -p 4000:80 friendlyhello
f176c313b58bf6b5f50d92a37b736632e03bdbd102bd6ef8283538d2dcbfe239
[jeshy@master DockerStudy]$ sudo docker container ls
CONTAINER ID与http:// localhost:4000上的内容匹配。
使用docker container stop结束进程,使用CONTAINER ID:
[jeshy@master DockerStudy]$ sudo docker container stop f176c313b58b
共享镜像
为了说明上述创建的内容的可移植性,上传已构建的镜像并在其他地方运行。当想要将容器部署到生产环境时,就需要知道和了解如何推送到注册表。注册表是存储库的集合,存储库是镜像的集合 - 类似于GitHub存储库,除了已经构建的代码。 注册表上的帐户可以创建许多存储库。Docker CLI默认使用Docker的公共注册表。
注意:这里使用Docker的公共注册表只是因为它是免费和预先配置的,有许多公共注册表可供选择,甚至可以使用Docker Trusted Registry设置自己的私有注册表。
使用Docker ID登录
如果没有Docker帐户,请在hub.docker.com上注册一个帐户,并记下用户名。
登录本地计算机上的Docker公共注册表:$ sudo docker login
标记镜像 Tag the image
将本地镜像与注册表上的存储库相关联的表示法是 username/repository:tag。建议使用标签,因为它是一种为Docker镜像提供版本标记的机制。给定一个存储库并用与上下文有意义的名称作标记,比如get-started:part2,这会将镜像植入get-started 存储库并将其标记为part2。现在,把它们放在一起来标记镜像。使用用户名、存储库和标记名称来运行docker标记镜像,以便将镜像上载到期望的目标位置。命令的语法格式如下:
docker tag image username/repository:tag
示例:
sudo docker tag friendlyhello gordon/get-started:part2
[jeshy@master DockerStudy]$ sudo docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
gordon/get-started part2 fe3b0a6a01ab 6 hours ago 131MB
friendlyhello latest fe3b0a6a01ab 6 hours ago 131MB
python 2.7-slim 0dc3d8d47241 3 weeks ago 120MB
hello-world latest 4ab4c602aa5e 3 months ago 1.84kB
发布镜像 Publish the image
上载已经标记的镜像到存储库:
docker push username/repository:tag
从远端存储库攫取并运行镜像
使用docker run命令,使用此命令在任何计算机上运行应用程序:
docker run -p 4000:80 username/repository:tag
如果本地镜像在计算机上不可用,则Docker会从存储库中攫取镜像。
$sudo docker run -p 4000:80 gordon/get-started:part2
Unable to find image 'gordon/get-started:part2' locally
part2: Pulling from gordon/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 gordon/get-started:part2
* Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
无论docker run在哪儿执行,都会pull你的镜像,以及Python和requirements.txt中的所有依赖项,并运行代码。不需要在主机上安装任何东西,它们在一个整洁的小包中一起运行。
以下是一些基本Docker命令列表,以及一些相关的命令:
docker build -t friendlyhello . # Create image using this directory's Dockerfile
docker run -p 4000:80 friendlyhello # Run "friendlyname" mapping port 4000 to 80
docker run -d -p 4000:80 friendlyhello # Same thing, but in detached mode
docker container ls # List all running containers
docker container ls -a # List all containers, even those not running
docker container stop <hash> # Gracefully stop the specified container
docker container kill <hash> # Force shutdown of the specified container
docker container rm <hash> # Remove specified container from this machine
docker container rm $(docker container ls -a -q) # Remove all containers
docker image ls -a # List all images on this machine
docker image rm <image id> # Remove specified image from this machine
docker image rm $(docker image ls -a -q) # Remove all images from this machine
docker login # Log in this CLI session using your Docker credentials
docker tag <image> username/repository:tag # Tag <image> for upload to registry
docker push username/repository:tag # Upload tagged image to registry
docker run username/repository:tag # Run image from a registry
Docker学习4-Containers - 容器的更多相关文章
- Docker学习第二天-容器
Docker 容器 容器是 Docker 又一核心概念. 简单的说,容器是独立运行的一个或一组应用,以及它们的运行态环境.对应的,虚拟机可以理解为模拟运行的一整套操作系统(提供了运行态环境和其他系统环 ...
- Docker学习之3——容器
容器(Container) 容器介绍: docker是通过容器来运行业务的,就像运行一个kvm虚拟机是一样的.容器其实就是从镜像创建的一个实例. 我们可以对容器进行增删改查,容器之间也是相互隔离的.和 ...
- Docker学习笔记——制作容器与容器概念
Docker能做些什么? 1.docker能够解决虚拟机能够解决的问题 2.隔离应用依赖 3.创建应用镜像并复制 4.创建容易分发的即启即用的应用 5.docker的想法是创建软件程序可移植的轻量容器 ...
- 【转】Docker学习_本地/容器文件互传(5)
将容器内文件拷贝到宿主机 docker cp <containerId>:/导出文件的位置/xxx.sql /宿主机的位置 示例:docker cp bf4c4fff338c:/root/ ...
- docker学习笔记:容器的网络设置
创建一个docker容器,docker系统会自动为该容器分配一个ip地址,通常是172.17开头. 我们可以在主机上用 docker inspect 命令 或者进入容器用ifconfig命令来查看容器 ...
- 优秀的云计算工程师需要学什么?云计算Docker学习路线
云计算工程师要学什么?随着互联网的快速发展,云计算这个词大家并不陌生,但是云计算究竟是做什么的,想要从事云计算要学习什么,很多都不知道,那么今天就给大家讲一下云计算. 云计算是基于互联网的相关服务的增 ...
- Docker学习笔记 - Docker容器内部署redis
Docker学习笔记(2-4)Docker应用实验-redist server 和client的安装使用 一.获取redis容器(含客户端和服务端) 二.创建服务端容器 1.在终端A中运行redis- ...
- Docker学习笔记 - Docker容器之间的连接
学习目标: 容器之间可以相互连接访问:: --link redis:redisAlias 准备工作 FROM ubuntu:14.04 RUN apt-get install -y ping RUN ...
- docker学习-lnmp+redis之搭建lnp容器服务
nginx+php7.0容器服务 本来想用单独的容器(nginx和php分开),但是因为是初学,php容器安装扩展的时候一直失败,所以就把centos+nginx+php放一起搭建了,优点是扩展简单, ...
- Docker学习之Docker容器基本使用
Docker学习之Docker容器基本使用 新建容器并启动 命令格式:docker run --options repository:tag 后台运行 命令格式:-d 已存在的容器相关操作 启动:do ...
随机推荐
- RocketMQ 消息消费
消息消费 难点:如何保证消息只消费一次? 消费模式: 1.单一消费模式:一条消息,仅被一个消费者进行消费. 如何进行负载?负载算法有 a.平均分配.b.平均轮询分配.c.一致性hash(不推荐).d. ...
- Javascript 随机数函数 学习之二:产生服从正态分布随机数
一.为什么需要服从正态分布的随机函数 一般我们经常使用的随机数函数 Math.random() 产生的是服从均匀分布的随机数,能够模拟等概率出现的情况,例如 扔一个骰子,1到6点的概率应该相等,但现实 ...
- element-ui switch组件源码分析整理笔记(二)
源码如下: <template> <div class="el-switch" :class="{ 'is-disabled': switchDisab ...
- Vue.js $nextTick
最近在学习vue.js.了解1.x的基础上再学习2.x的vue.两个版本的确是不会像angular这样1.x和2.x相差甚远.所以学习起来其实还是有很大的关联.但是,终归来说.两者还是有语法上的细微差 ...
- CSS控制Span强制换行亲测
span { word-wrap: break-word; word-break: break-all; white-space: pre-wrap !important; }
- 腾讯TBS X5 WebView的简单使用
工作中经常涉及H5网页的加载工作,最多使用的就是安卓系统控件WebView,但是当网页内容比较多的时候,需要等待很久才能加载完,加载完后用户才能看到网页中的内容,这样用户需要等很久,体验很差. 那能不 ...
- word2vec前世今生
word2vec前世今生 2013年,Google开源了一款用于词向量计算的工具--word2vec,引起了工业界和学术界的关注.首先,word2vec可以在百万数量级的词典和上亿的数据集上进行高效地 ...
- LeetCode题解之 Odd Even Linked List
1.题目描述 2.问题分析 将链表拆分成两个,奇数节点形成一个链表,偶数节点形成另外一个链表,最后将偶数节点链表加在奇数节点链表后面. 3.代码 ListNode* oddEvenList(ListN ...
- EFCore中SQLSERVER 2008 的分页问题
自SQLSERVER 2012起新增了 Offset Fetch 语法,因此EFCore默认是以此语法生成相应的分页语句的. 如果我们的目标数据库低于 2012,那么EFCore默认生成的语句在执行的 ...
- windows系统相关命令及问题排查实践
1. 如何查看哪个端口被哪个程序占用? Netstat –ano|findstr "80" ->找到监听80端口的pid tasklist|findstr “<PID号 ...