文章目录
1、什么是镜像
Docker镜像是一个特殊的文件系统,这个文件系统封装了运行时需要的库、资源、应用等,是Docker运行容器的前提,可以被用来创建容器,镜像是一个只读的模板,一个独立的文件系统,包括运行容器所需的数据,可以用来创建新的容器。
Docker容器镜像是一个轻量级的、独立的、可执行的软件包,它包含了运行应用程序所需的一切:代码、运行时、系统工具、系统库和设置。
镜像组成:
操作系统、核心代码、系统工具、系统库、运行时的环境
2、制作一个python类简单镜像
1、配置Dockerfile文件
FROM python:2.7-slim #导入要使用的基础系统(基础镜像)
WORKDIR /app #进入容器后,会进入的文件夹
ADD . /app #复制linux中当前目录下的内容到容器的/app目录下
RUN pip install --trusted-host pypi.python.org -r requirements.txt #在容器内部执行的命令(容器启动之前)
EXPOSE 80 #容器暴露80端口,监听80端口
ENV NAME World #定义环境变量NAME赋值为world
ENV AUTHOR cali #定义环境变量AUTHOR赋值为cali
CMD ["python","app.py"] #启动容器时执行的命令
2、编辑requirements.txt文件
[root@docker_server mydocker]# vim requirements.txt
[root@docker_server mydocker]# cat requirements.txt
Flask
Redis
3、编辑执行程序app.py
[root@docker_server mydocker]# vim app.py
[root@docker_server mydocker]# cat 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)
4、制作镜像
[root@docker_server mydocker]# docker build -t py-mirror-1:1.0 .
Dockerfile中的指令会一条条的执行
[+] Building 88.8s (9/9) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 273B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/python:2.7-slim 3.5s
=> [1/4] FROM docker.io/library/python:2.7-slim@sha256:6c1ffdff499e29ea663e6e67c9b6b9a3b401d554d2c9f061f9a45344e3992363 25.7s
=> => resolve docker.io/library/python:2.7-slim@sha256:6c1ffdff499e29ea663e6e67c9b6b9a3b401d554d2c9f061f9a45344e3992363 0.0s
=> => sha256:6c1ffdff499e29ea663e6e67c9b6b9a3b401d554d2c9f061f9a45344e3992363 1.86kB / 1.86kB 0.0s
=> => sha256:b68d40df862ac07e8955ea0fc0c5454cb4245b6165e79bc8ea2cc69170d9ba62 1.16kB / 1.16kB 0.0s
=> => sha256:eeb27ee6b89303f04a917e457eda70d032b1574ec80d0b4ea410d478a714538f 7.95kB / 7.95kB 0.0s
=> => sha256:123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b 27.10MB / 27.10MB 21.8s
=> => sha256:dd1cd66375238ded36eeaea07567a1997f7fd76611a517119ec39fee9b9e887f 2.75MB / 2.75MB 6.1s
=> => sha256:0c4e6d630f2cb5403efb04352c40ed72f1884355253a0cc15486c4e6ca998111 19.66MB / 19.66MB 9.4s
=> => sha256:13e9cd8f0ea14403e44c745ea5212658b6600021f6beb6fc484f2570db89b143 2.18MB / 2.18MB 7.8s
=> => extracting sha256:123275d6e508d282237a22fefa5aef822b719a06496444ea89efa65da523fc4b 2.1s
=> => extracting sha256:dd1cd66375238ded36eeaea07567a1997f7fd76611a517119ec39fee9b9e887f 0.2s
=> => extracting sha256:0c4e6d630f2cb5403efb04352c40ed72f1884355253a0cc15486c4e6ca998111 1.2s
=> => extracting sha256:13e9cd8f0ea14403e44c745ea5212658b6600021f6beb6fc484f2570db89b143 0.3s
=> [internal] load build context 0.0s
=> => transferring context: 264B 0.0s
=> [2/4] WORKDIR /app 0.2s
=> [3/4] ADD . /app 0.0s
=> [4/4] RUN pip install --trusted-host pypi.python.org -r requirements.txt 59.2s
=> exporting to image 0.1s
=> => exporting layers 0.1s
=> => writing image sha256:815042b196bc69451c87bb40c75b43190194c02f1d392d0ff2759bb90702dd7f 0.0s
=> => naming to docker.io/library/py-mirror-1:1.0 0.0s
[root@docker_server mydocker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
py-mirror-1 1.0 815042b196bc 36 seconds ago 159MB
运行:
[root@docker_server mydocker]# docker run -d -p 5080:80 --name py-hello-1 py-mirror-1:1.0
7ffe3215f4467d6ddabda40584d2dccc2f5c59ee50ae1258d22e7164b51e4b49
[root@docker_server mydocker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7ffe3215f446 py-mirror-1:1.0 "python app.py" 6 seconds ago Up 5 seconds 0.0.0.0:5080->80/tcp, :::5080->80/tcp py-hello-1
5、启动一个redis数据库
上面启动制作镜像容器后访问页面出现:
Visits cannot connect to Redis, counter disabled
需要再启动一个redis进行连接:
创建一个redis数据库:
[root@docker_server ~]# docker run -d -p 6379:6379 --name sc-redis-1 redis
Unable to find image 'redis:latest' locally
latest: Pulling from library/redis
5b5fe70539cd: Pull complete
a1bc4b7ad0f0: Pull complete
a33d2f01ead9: Pull complete
94b33095e71c: Pull complete
d3c2b649b97c: Pull complete
8a5bf7f0acd7: Pull complete
Digest: sha256:6ccde0cb87c24c09b1970802b10e702ab4491ac932b79f69682609787379fa42
Status: Downloaded newer image for redis:latest
c2ee11a514b155f2b07de163182721d00a95593aef60d3f75a2dff4157a0bb77
再启动一个制作镜像的容器,连接redis数据库(链接刚创建的redis容器)
[root@docker_server ~]# docker run -d -p 5081:80 --name py-hello-2 --link sc-redis-1:redis py-mirror-1:1.0
d63316b880c07c2b9f0ebd5d80d141c359684601ddaaa42d0248450c7bfad069
[root@docker_server ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d63316b880c0 py-mirror-1:1.0 "python app.py" 4 seconds ago Up 4 seconds 0.0.0.0:5081->80/tcp, :::5081->80/tcp py-hello-2
c2ee11a514b1 redis "docker-entrypoint.s…" 3 minutes ago Up 3 minutes 0.0.0.0:6379->6379/tcp, :::6379->6379/tcp sc-redis-1
再次去访问web页面redis会记录访问次数并显示在屏幕:
Hello World
Hostname: d63316b880c0
Visits 6
3、持续集成/持续交付(CI/CD)–Jenkins
CI/CD的英文全称是Continuous Integration/Continuous Delivery或Continuous Integration/Continuous Deployment。
持续集成(Continuous integration)是一种软件开发实践,即团队开发成员经常集成他们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。
它的好处主要有两个。第一,快速发现错误。每完成一点更新,就集成到主干,可以快速发现错误,定位错误也比较容易。第二,防止分支大幅偏离主干。如果不是经常集成,主干又在不断更新,会导致以后集成的难度变大,甚至难以集成。持续集成的目的,就是让产品可以快速迭代,同时还能保持高质量。它的核心措施是,代码集成到主干之前,必须通过自动化测试。只要有一个测试用例失败,就不能集成。
持续交付(Continuous delivery)是一种软件工程手法,让软件产品的产出过程在一个短周期内完成,以保证软件可以稳定、持续的保持在随时可以发布的状况。它指的是,频繁地将软件的新版本,交付给质量团队或者用户,以供评审。如果评审通过,代码就进入生产阶段。
持续交付可以看作持续集成的下一步。它强调的是,不管怎么更新,软件是随时随地可以交付的
4、镜像的分层思想
镜像分层是Docker镜像的一个重要概念。Docker镜像是由一系列层来构成的,每层代表Dockerfile中的一条指令。每个层都是只读的,当容器启动时,Docker会将这些层联合起来,形成一个可读写的容器文件系统。这种分层的机制使得Docker镜像可以被高效地构建、传输和存储
镜像里的系统使用宿主机的内核,基础镜像里有操作系统的库、运行环境、依赖软件等,在镜像制作过程中每RUN一次就会多一层;层数越多消耗的内层就越大
为什么 Docker 镜像要采用这种分层结构呢?
最大的一个好处就是 - 共享资源。
比如:有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
容器启动的时候,内核启动bootfs后直接将基础镜像加载,然后一层一层的加载,自下而上
容器运行后访问文件的时候,从上而下,从可写层,一层一层往下访问
5、Dockerfile指令
FROM:指定基础镜像
WORKDIR:指定容器进入时在那个目录(工作目录)
COPY:复制宿主机的文件后目录到某个目录下
ADD:复制宿主机的文件或者目录到某个目录下,压缩文件会自动解压
RUN:运行命令,在制作镜像时运行
CMD:运行的第一个命令,启动容器时运行
ENTRYPOINT:启动容器时运行的命令,使用docker run启容器时会接收到docker
run传递的参数,当CMD与ENTRYPOINT都存在时CMD中的内容会成为
ENTRYPOINT的参数(位置参数)
ENV:定义环境变量
EXPOSE:声明开放端口
ARG:传递参数(先定义好,在制作docker build时传递参数–build-arg 【参数】)
VOLUME:在容器里使用卷(将容器里的某个路径挂载到宿主机的卷上)
STOPSIGNAL:阻止信号
HEALTHCHECK:检测是否能正常运行,可以对外提供服务
SHELL:SHELL指令允许覆盖用于SHELL形式命令的默认SHELL