Docker 快速入门
“这是一个非常棒的docker学习历程。我把一个国外的docker实践入门教学进行了简略的翻译,比起国内博客学习的总结性文章,它更注重让小白在实战背景下容易理解与感悟,激发萌新自我疏理总结实战演练下的小细节。”
文章目录
Docker 快速入门
1. 运行redis容器
2. 运行web容器
3. 编排镜像
4. 构建node.js镜像
4.1 dockerfile基础定义
4.2 npm install
4.3 应用配置
4.4 构建并运行镜像
4.5 运行添加环境变量
5. OnBuild优化Dockerfile
6. 忽略文件`.dockerignore`
6.1 Docker Ignore
6.2 Docker 构建安全上下文
6.3 优化构建
7. 容器持久化数据
8. 容器之间的交流
9. Docker 网络
9.1 创建网络
9.2 连接网络
9.3 连接两个容器
9.4 创建别名
9.5 断开容器连接
10. 使用卷持久化存储
10.1 --volumes,-v
10.2 --volumes-from
10.3 只读卷
11. 管理日志
12. 容器运行策略
13. 容器元数据与标签
14. 负载平衡的容器
14.1 NGINX Proxy
14.2 单机
14.2 集群
15. 编排docker-compose
16. docker stats统计信息
17. dockerfile多阶段构建创建优化docker镜像
18. docker ps输出格式
19. Docker非root特权配置
1. 运行redis容器
第一个任务是识别配置为运行Redis的Docker映像的名称。使用Docker,所有容器都是基于Docker映像启动的。这些图像包含启动流程所需的所有内容;主机不需要任何配置或依赖项。
$ docker search redis NAME DESCRIPTION STARS OFFICIAL AUTOMATED redis Redis is an open source key-value store that… 9971 [OK] sameersbn/redis 83 [OK] grokzen/redis-cluster Redis cluster 3.0, 3.2, 4.0, 5.0, 6.0, 6.2 79 rediscommander/redis-commander Alpine image for redis-commander - Redis man… 66 [OK] redislabs/redisearch Redis With the RedisSearch module pre-loaded… 39 redislabs/redisinsight RedisInsight - The GUI for Redis 35 kubeguide/redis-master redis-master with "Hello World!" 33 redislabs/redis Clustered in-memory database engine compatib… 31 oliver006/redis_exporter Prometheus Exporter for Redis Metrics. Supp… 30 redislabs/rejson RedisJSON - Enhanced JSON data type processi… 27 arm32v7/redis Redis is an open source key-value store that… 24 redislabs/redisgraph A graph database module for Redis 16 [OK] arm64v8/redis Redis is an open source key-value store that… 15 redislabs/redismod An automated build of redismod - latest Redi… 15 [OK] redislabs/rebloom A probablistic datatypes module for Redis 14 [OK] webhippie/redis Docker image for redis 11 [OK] insready/redis-stat Docker image for the real-time Redis monitor… 10 [OK] s7anley/redis-sentinel-docker Redis Sentinel 10 [OK] redislabs/redistimeseries A time series database module for Redis 10 goodsmileduck/redis-cli redis-cli on alpine 9 [OK] centos/redis-32-centos7 Redis in-memory data structure store, used a… 5 clearlinux/redis Redis key-value data structure server with t… 3 wodby/redis Redis container image with orchestration 1 [OK] tiredofit/redis Redis Server w/ Zabbix monitoring and S6 Ove… 1 [OK] xetamus/redis-resource forked redis-resource 0 [OK] $
使用搜索命令,Jane已经确定Redis Docker Image被称为Redis,并希望运行最新版本。因为Redis是一个数据库,Jane想在她继续工作的时候把它作为后台服务运行。
要完成这一步,在后台启动一个容器,运行一个基于官方图像的Redis实例。
Docker CLI有一个名为run的命令,它将基于Docker映像启动一个容器。结构是docker运行<options> <image-name>
默认情况下,Docker将在前台运行一个命令。要在后台运行,需要指定选项-d。
$ docker run -d redis 66a23eb0c3fd7ce1099f0eef043303eb286084a87e6047e851057d0ecc634ee0 $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 66a23eb0c3fd redis "docker-entrypoint.s…" About a minute ago Up About a minute 6379/tcp zen_archimedes `docker inspect <friendly-name|container-id>`命令提供了运行容器的详细信息,如IP地址等。 `docker logs <friendly-name|container-id>`将显示容器写入标准错误或标准输出的消息。 #静态映射端口 $ docker run -d --name redisHostPort -p 6379:6379 redis:latest 00d11bf6c9217aa43646c32779a29d62d854e90ae3cfe70e72e61016db49fb7c #动态映射端口 $ docker run -d --name redisDynamic -p 6379 redis:latest 56a6612f70b1f35097da220339cc1ec4c3ae84137757e803aa59e41c61523a11 $ docker port redisDynamic 6379 0.0.0.0:32768 #已经启动了多个redis实例 $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 56a6612f70b1 redis:latest "docker-entrypoint.s…" 58 seconds ago Up 57 seconds 0.0.0.0:32768->6379/tcp redisDynamic 00d11bf6c921 redis:latest "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 0.0.0.0:6379->6379/tcp redisHostPort 66a23eb0c3fd redis "docker-entrypoint.s…" 5 minutes ago Up 5 minutes 6379/tcp zen_archimedes
缺省情况下,主机端口映射为0.0.0.0,即所有IP地址。在定义端口映射时,可以指定一个特定的IP地址,例如-p 127.0.0.1:6379:6379
默认情况下,Docker将运行可用的最新版本。如果需要一个特定的版本,它可以被指定为一个标记,例如,version 3.2将被docker run -d redis:3.2。
由于这是Jane第一次使用Redis映像,它将被下载到Docker Host机器上。
让数据持久存储
$ docker run -d --name redisMapped -v /opt/docker/data/redis:/data redis 71e3cfca3344c9eaa4102761fad59d135c3233b56e960eebd5b650d72996936e
Docker允许您使用$PWD
作为当前目录的占位符。
2. 运行web容器
Docker映像从一个基本映像开始。基本映像应该包括应用程序所需的平台依赖项,例如,安装JVM或CLR。
这个基本映像定义为Dockerfile中的一条指令。Docker映像是基于Dockerfile的内容构建的。Dockerfile是描述如何部署应用程序的说明列表。
在这个例子中,我们的基础图像是Nginx的Alpine版本。这提供了Linux Alpine发行版上配置的web服务器。
写一个网页
$ vim index.html <h1>Hello World</h1>
创建dockerfile
FROM nginx:alpine COPY . /usr/share/nginx/html
构建镜像
$ docker build -t webserver-image:v1 . Sending build context to Docker daemon 3.072kB Step 1/2 : FROM nginx:alpine ---> 513f9a9d8748 Step 2/2 : COPY . /usr/share/nginx/html ---> ae7287f132f3 Successfully built ae7287f132f3 Successfully tagged webserver-image:v1 $ docker build -t webserver-image:v1 . Sending build context to Docker daemon 3.072kB Step 1/2 : FROM nginx:alpine ---> 513f9a9d8748 Step 2/2 : COPY . /usr/share/nginx/html ---> Using cache ---> ae7287f132f3 Successfully built ae7287f132f3 Successfully tagged webserver-image:v1 $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE webserver-image v1 ae7287f132f3 15 seconds ago 22.9MB
通过镜像运行容器
$ docker run -d -p 80:80 webserver-image:v1
测试web
$ curl ip <h1>Hello World</h1>
3. 编排镜像
所有Docker映像都从一个基本映像开始。基本映像是来自Docker 官方仓库用于启动容器的相同映像。除了图像名称,我们还可以包含图像标签,以指示我们想要的特定版本,默认情况下,这是最新的版本。
这些基本映像用作运行应用程序所需的附加更改的基础。例如,在这个场景中,在部署静态HTML文件之前,我们需要在系统上配置并运行NGINX。因此,我们想使用NGINX作为我们的基本映像。Dockerfile是简单的文本文件
FROM nginx:1.11-alpine
定义了基本映像之后,我们需要运行各种命令来配置映像。有很多命令可以帮助实现这一点,主要的两个命令是COPY和RUN。
RUN <command>允许您像在命令提示符中那样执行任何命令,例如安装不同的应用程序包或运行构建命令。RUN的结果会持久化到映像中,因此不要在磁盘上留下任何不必要的或临时的文件,这一点很重要,因为这些文件将包含在映像中。
COPY <src> <dest>允许您将文件从包含Dockerfile的目录复制。
已经为您创建了一个新的index.html文件,我们想从我们的容器中提供该文件。在FROM命令后面的下一行,使用COPY命令将index.html复制到/usr/share/nginx/html目录中。
$ vim index.html <h1>Hello World</h1>
FROM nginx:1.11-alpine COPY index.html /usr/share/nginx/html/index.html
将我们的文件复制到映像中并下载了所有依赖项后,您需要定义需要访问哪个端口应用程序。
使用EXPOSE <port>
命令可以告诉Docker应该打开哪些端口,可以绑定到哪些端口。您可以在一条命令中定义多个端口,例如EXPOSE 80433
或EXPOSE 7000-8000
FROM nginx:1.11-alpine COPY index.html /usr/share/nginx/html/index.html EXPOSE 80
配置好Docker映像并定义了我们想要访问的端口后,现在我们需要定义启动应用程序的命令。
Dockerfile中的CMD行定义了启动容器时要运行的默认命令。如果命令需要参数,那么建议使用一个数组,例如["cmd", "-a", "arga value", "-b", "argb-value"],这将被组合在一起,命令cmd -a" arga value" -b argb-value将被运行。
运行NGINX的命令为NGINX -g daemon off;将此设置为Dockerfile中的默认命令。
CMD的另一种方法是ENTRYPOINT。虽然CMD可以在容器启动时被重写,但ENTRYPOINT定义了一个命令,在容器启动时可以将参数传递给它。
在这个例子中,NGINX将是关闭-g守护进程的入口点;默认的命令。
FROM nginx:1.11-alpine COPY index.html /usr/share/nginx/html/index.html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
写完Dockerfile后,你需要使用docker构建将它转换成一个映像。build命令接受一个包含Dockerfile的目录,执行步骤并将映像存储在本地Docker引擎中。如果由于错误而失败,则构建将停止。
docker build -t my-nginx-image:latest . docker images
使用来自build命令的ID结果或您分配给它的友好名称启动新构建映像的实例。
NGINX被设计为后台服务,所以你应该包含选项-d。要使web服务器可访问,使用-p 80:80
将其绑定到端口80
$ docker run -d -p 80:80 my-nginx-image:latest $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 34e0b44c067f my-nginx-image:latest "nginx -g 'daemon of…" About a minute ago Up About a minute 0.0.0.0:80->80/tcp, 443/tcp gracious_ride $ curl -i http://ip HTTP/1.1 200 OK Server: nginx/1.11.13 Date: Tue, 28 Sep 2021 08:17:44 GMT Content-Type: text/html Content-Length: 21 Last-Modified: Tue, 28 Sep 2021 08:11:49 GMT Connection: keep-alive ETag: "6152ce45-15" Accept-Ranges: bytes <h1>Hello World</h1>
4. 构建node.js镜像
4.1 dockerfile基础定义
正如我们在前一个场景中所描述的,所有映像都从一个基本映像开始,理想情况下,该映像尽可能接近您所需的配置。Node.js为每个发布版本提供了带有标签的预构建映像。
Node:0.0的图像为Node:10-alpine。这是一个基于 Alpine-based的构建,比官方形象更小和更流线型。
除了基本映像,我们还需要创建应用程序运行的基本目录。使用RUN <命令>,我们可以像从命令shell中运行一样执行命令,通过使用mkdir,我们可以创建目录.
我们可以使用WORKDIR <目录>定义一个工作目录,以确保所有未来的命令都是从相对于我们的应用程序的目录执行的。
在单独的行上设置FROM <image>:<tag>、RUN <command>和WORKDIR <directory>,以配置用于部署应用程序的基本环境。
Dockerfile内容:
FROM node:10-alpine RUN mkdir -p /src/app WORKDIR /src/app
4.2 npm install
在前面的集合中,我们配置了配置的基础以及希望如何部署应用程序。下一个阶段是安装运行应用程序所需的依赖项。对于Node.js,这意味着运行NPM install。
为了将构建时间保持在最小,Docker将在Dockerfile中缓存一行代码的执行结果,以便在将来的构建中使用。如果发生了更改,Docker将使当前行和以下所有行无效,以确保所有行都是最新的。
对于NPM,我们只希望在包中有东西时重新运行NPM install。Json文件已经改变。如果没有任何改变,那么我们可以使用缓存版本来加速部署。使用COPY包。我们可以使RUN npm install命令失效,如果包。Json文件已经改变。如果文件没有更改,那么缓存将不会失效,并且将使用npm install命令的缓存结果。
Dockerfile更新内容:
FROM node:10-alpine RUN mkdir -p /src/app WORKDIR /src/app COPY package.json /src/app/package.json RUN npm install
如果你不想使用缓存作为构建的一部分,那么设置选项--no-cache=true
作为docker构建命令的一部分。
4.3 应用配置
在安装了依赖项之后,我们希望复制应用程序的其余源代码。拆分依赖项的安装并复制源代码使我们能够在需要时使用缓存。
如果我们在运行npm install之前复制我们的代码,那么它每次都会运行,因为我们的代码会发生变化。通过复制只是包。Json,我们可以确保缓存是无效的,只有当我们的包内容已经改变。
在Dockerfile中创建所需的步骤,以完成应用程序的部署。
我们可以使用copy复制Dockerfile所在的整个目录<dest dir>。
复制源代码之后,使用EXPOSE <port>定义应用程序需要访问的端口。
最后,需要启动应用程序。使用Node.js的一个巧妙技巧是使用npm start命令。这看起来在包里。Json文件,了解如何启动保存重复命令的应用程序。
FROM node:10-alpine RUN mkdir -p /src/app WORKDIR /src/app COPY package.json /src/app/package.json RUN npm install COPY . /src/app EXPOSE 3000 CMD [ "npm", "start" ]
4.4 构建并运行镜像
$ docker build -t my-nodejs-app . $ docker run -d --name my-running-app -p 3000:3000 my-nodejs-app
您可以使用curl测试容器是否可访问。如果应用程序响应,那么您就知道一切都已正确启动。
$ curl http://docker:3000 <!DOCTYPE html><html><head><title>Express</title><link rel="stylesheet" href="/stylesheets/style.css"></head><body><h1>Express</h1><p>Welcome to Express</p></body></html>
4.5 运行添加环境变量
Docker映像应该设计成可以从一个环境传输到另一个环境,而不需要做任何更改或重新构建。通过遵循这个模式,您可以确信,如果它在一个环境(如登台)中工作,那么它也将在另一个环境(如生产环境)中工作。
使用Docker,可以在启动容器时定义环境变量。例如,对于Node.js应用程序,您应该在生产环境中运行时为NODE_ENV定义一个环境变量。
使用-e选项,可以将名称和值设置为-e NODE_ENV=production
$ docker run -d --name my-production-running-app -e NODE_ENV=production -p 3000:3000 my-nodejs-app