公司要新招美女跟我学docker,你来吗?
Posted ghostwritten
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了公司要新招美女跟我学docker,你来吗?相关的知识,希望对你有一定的参考价值。
“这是一个非常棒的docker学习历程。我把一个国外的docker实践入门教学进行了简略的翻译,比起国内博客学习的总结性文章,它更注重让小白在实战背景下容易理解与感悟,激发萌新自我疏理总结实战演练下的小细节。”
文章目录
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
5. OnBuild优化Dockerfile
虽然Dockerfile是按从上到下的顺序执行的,但当该映像用作另一个映像的基础时,您可以触发一条指令在稍后的时间执行。
ONBUILD指令可以为镜像添加触发器。
当我们在一个Dockerfile文件中加上ONBUILD指令,该指令对利用该Dockerfile构建镜像(比如为A镜像)不会产生实质性影响。
但是当我们编写一个新的Dockerfile文件来基于A镜像构建一个镜像(比如为B镜像)时,这时构造A镜像的Dockerfile文件中的ONBUILD指令就生效了,在构建B镜像的过程中,首先会执行ONBUILD指令指定的指令,然后才会执行其它指令。
需要注意的是,如果是再利用B镜像构造新的镜像时,那个ONBUILD指令就无效了,也就是说只能再构建子镜像中执行,对孙子镜像构建无效。其实想想是合理的,因为在构建子镜像中已经执行了,如果孙子镜像构建还要执行,相当于重复执行,这就有问题了。
利用ONBUILD指令,实际上就是相当于创建一个模板镜像,后续可以根据该模板镜像创建特定的子镜像,需要在子镜像构建过程中执行的一些通用操作就可以在模板镜像对应的dockerfile文件中用ONBUILD指令指定。 从而减少dockerfile文件的重复内容编写。
下面是Node.js的OnBuild Dockerfile
。与前面的场景不同,应用程序指定命令以ONBUILD
作为前缀。
Dockerfile1:
FROM node:7
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ONBUILD COPY package.json /usr/src/app/
ONBUILD RUN npm install
ONBUILD COPY . /usr/src/app
CMD [ "npm", "start" ]
docker build -t node:7-onbuild -f Dockerfile1
结果是,我们可以构建这个映像,但在将构建的映像用作基本映像之前,不会执行应用程序特定的命令。然后,它们将作为基本映像构建的一部分执行。
有了复制代码、安装依赖项和启动应用程序的所有逻辑后,在应用程序级别上需要定义的唯一方面就是要公开哪个端口。
创建OnBuild
映像的好处是,我们的Dockerfile现在更简单,可以轻松地跨多个项目重用,而不必重新运行相同的步骤,以提高构建时间。
dockerfile2:
FROM node:7-onbuild
EXPOSE 3000
已经为您创建了上一步中的Dockerfile。基于OnBuild docker
文件构建映像与之前相同。OnBuild命令将像在基础Dockerfile中一样执行。
总之,唯有 ONBUILD
是为了帮助别人定制自己而准备的。而不是为了构建当前镜像的。
docker build -t my-nodejs-app -f dockerfile2
docker run -d --name my-running-app -p 3000:3000 my-nodejs-app
curl http://ip:3000
6. 忽略文件.dockerignore
6.1 Docker Ignore
为了防止敏感文件或目录被错误地包含在映像中,您可以添加一个名为.dockerignore
的文件。
Dockerfile将工作目录复制到Docker映像中。因此,这将包括潜在的敏感信息,如我们希望在映像外部管理的密码文件。
$ ls
Dockerfile cmd.sh passwords.txt
$ cat Dockerfile
FROM alpine
ADD . /app
COPY cmd.sh /cmd.sh
CMD ["sh", "-c", "/cmd.sh"]
$ cat cmd.sh
echo "Hello World"
$ cat passwords.txt
admin:admin
$ docker build -t password .
Sending build context to Docker daemon 4.096kB
Step 1/4 : FROM alpine
---> 3fd9065eaf02
Step 2/4 : ADD . /app
---> 8e7bc5dac978
Step 3/4 : COPY cmd.sh /cmd.sh
---> ec486638d561
Step 4/4 : CMD ["sh", "-c", "/cmd.sh"]
---> Running in fe4cba7a87b2
Removing intermediate container fe4cba7a87b2
---> 4c270e87d27c
Successfully built 4c270e87d27c
Successfully tagged password:latest
$ docker run password ls /app
Dockerfile
cmd.sh
passwords.txt
这将包括密码文件。
下面的命令将在.dockerignore
文件中包含password .txt
,并确保它不会意外地出现在容器中。dockerignore文件将存储在源代码管理中,并与团队共享,以确保每个人都是一致的。
echo passwords.txt >> .dockerignore
.dockerignore
文件支持目录和正则表达式来定义限制,非常类似于.gitignore
。这个文件还可以用来提高构建时间,我们将在下一步研究这个问题。
构建映像,因为Docker Ignore文件不应该包括密码文件。
$ docker build -t nopassword .
Sending build context to Docker daemon 4.096kB
Step 1/4 : FROM alpine
---> 3fd9065eaf02
Step 2/4 : ADD . /app
---> 36ee8b3bc4ee
Step 3/4 : COPY cmd.sh /cmd.sh
---> a4c8fc953352
Step 4/4 : CMD ["sh", "-c", "/cmd.sh"]
---> Running in 5b7774763eca
Removing intermediate container 5b7774763eca
---> b6b6eac92cce
Successfully built b6b6eac92cce
Successfully tagged nopassword:latest
$ docker run nopassword ls /app
Dockerfile
cmd.sh
如果您需要使用密码作为RUN命令的一部分,那么您需要复制、执行和删除文件作为单个RUN命令的一部分。只有Docker容器的最终状态被持久化到映像中。
6.2 Docker 构建安全上下文
dockerignore
文件可以确保Docker映像中不包含敏感细节。但是,它们也可以用来提高映像的构建时间。
在环境中,已经创建了100M的临时文件。Dockerfile永远不会使用这个文件。当您执行构建命令时,Docker将整个路径内容发送给引擎,以便它计算要包含哪些文件。因此,发送100M文件是不需要的,并创建了一个较慢的构建。
您可以通过执行该命令看到100M的影响。
$ docker build -t large-file-context .
Sending build context to Docker daemon 104.9MB
Step 1/4 : FROM alpine
---> 3fd9065eaf02
Step 2/4 : ADD . /app
---> cb1e74c524af
Step 3/4 : COPY cmd.sh /cmd.sh
---> e3dbbbd57ddf
Step 4/4 : CMD ["sh", "-c", "/cmd.sh"]
---> Running in 5fcb5e771266
Removing intermediate container 5fcb5e771266
---> 7e398a079fb0
Successfully built 7e398a079fb0
Successfully tagged large-file-context:latest
在下一步中,我们将演示如何提高构建的性能。
明智的做法是忽略.git
目录以及在映像中下载/构建的依赖项,比如node_modules
。在Docker容器中运行的应用程序永远不会使用它们,只会增加构建过程的开销。
6.3 优化构建
以同样的方式,我们使用.dockerignore文件来排除敏感文件,我们可以使用它来排除我们不想在构建期间发送到Docker构建上下文的文件。
要加快构建速度,只需在忽略文件中包含大文件的文件名。
echo big-temp-file.img >> .dockerignore
当我们重建图像时,它将会快得多,因为它不需要复制100M文件。
$ docker build -t no-large-file-context .
Sending build context to Docker daemon 4.096kB
Step 1/4 : FROM alpine
---> 3fd9065eaf02
Step 2/4 : ADD . /app
---> Using cache
---> 4a1be3423c29
Step 3/4 : COPY cmd.sh /cmd.sh
---> Using cache
---> e30db2162cca
Step 4/4 : CMD ["sh", "-c", "/cmd.sh"]
---> Using cache
---> 4d4964ddbb00
Successfully built 4d4964ddbb00
Successfully tagged no-large-file-context:latest
当忽略.git
这样的大目录时,这种优化会产生更大的影响。
7. 容器持久化数据
数据容器是唯一负责存储/管理数据的容器。
与其他容器一样,它们由主机系统管理。然而,当您执行docker ps命令时,它们不会运行。
要创建数据容器,我们首先要创建一个具有知名名称的容器以供将来参考。我们使用busybox作为基础,因为它体积小,重量轻,以防我们想要探索和移动容器到另一个主机。
在创建容器时,我们还提供了一个-v选项来定义其他容器读取/保存数据的位置。
$ docker create -v /config --name dataContainer busybox
容器就绪后,我们现在可以将文件从本地客户端目录复制到容器中。
下面的命令将config.conf文件复制到dataContainer和config.conf
目录中。
$ docker cp config.conf dataContainer:/config/
现在我们的Data Container
有了配置,我们可以在启动需要配置文件的依赖容器时引用该容器。
使用——volumes-from <container>
选项,我们可以使用正在启动的容器中来自其他容器的挂载卷。在这种情况下,我们将启动一个Ubuntu容器,它引用了我们的数据容器。当我们列出config目录时,它将显示来自附加容器的文件。
$ docker run --volumes-from dataContainer ubuntu ls /config
config.conf
如果/config
目录已经存在,那么volumes-from
将被覆盖并成为所使用的目录。可以将多个卷映射到一个容器。
如果我们想将Data Container移动到另一台机器,那么我们可以将其导出到.tar文件。
$ docker export dataContainer > dataContainer.tar
命令docker import dataContainer.tar
会将数据容器导入到docker中。
8. 容器之间的交流
连接到容器最常见的场景是应用程序连接到数据存储。创建链接时的关键方面是容器的名称。所有容器都有名称,但为了在处理链接时更容易一些,为所连接的源容器定义一个友好的名称是很重要的。
运行一个友好的名称为redis-server的redis服务器,我们将在下一步连接它。这将是源容器。
$ docker run -d --name redis-server redis
Redis是一个快速的、开源的键值数据存储。
要连接到源容器,在启动新容器时使用--link <container-name|id>:<alias>
选项。容器名引用上一步中定义的源容器,而别名定义主机的友好名称。
通过设置别名,我们可以将应用程序的配置方式与基础设施的调用方式分开。这意味着应用程序配置在连接到其他环境时不需要更改。
在这个例子中,我们打开一个链接到redis-server
的Alpine
容器。我们已经将别名定义为redis。当一个链接被创建时,Docker将做两件事。
首先,Docker将基于链接到容器的环境变量设置一些环境变量。这些环境变量为您提供了一种通过已知名称引用端口和IP地址等信息的方法。
可以使用env命令输出所有环境变量。例如:
$ docker run --link redis-server:redis alpine env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=bae49bf11c01
REDIS_PORT=tcp://172.18.0.2:6379
REDIS_PORT_6379_TCP=tcp://172.18.0.2:6379
REDIS_PORT_6379_TCP_ADDR=172.18.0.2
REDIS_PORT_6379_TCP_PORT=6379
REDIS_PORT_6379_TCP_PROTO=tcp
REDIS_NAME=/angry_franklin/redis
REDIS_ENV_GOSU_VERSION=1.12
REDIS_ENV_REDIS_VERSION=6.2.5
REDIS_ENV_REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-6.2.5.tar.gz
REDIS_ENV_REDIS_DOWNLOAD_SHA=4b9a75709a1b74b3785e20a6c158cab94cf52298aa381eea947a678a60d551ae
HOME=/root
通过创建链接,您可以以与在您的网络中运行的服务器相同的方式ping源容器。
$ docker run --link redis-server:redis alpine ping -c 1 redis
PING redis (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.202 ms
--- redis ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.202/0.202/0.202 ms
通过创建链接,应用程序可以以通常的方式与源容器进行连接和通信,而无需考虑两个服务都运行在容器中这一事实。
这是一个简单的node.js应用程序,它使用主机名redis连接到redis。
$ docker run -d -p 3000:3000 --link redis-server:redis katacoda/redis-node-docker-example
发送一个HTTP请求到应用程序将存储请求在Redis和返回一个计数。如果发出多个请求,就会看到计数器的递增,因为条目被持久化了。
$ curl ip:3000
This page was generated after talking to redis.
Application Build: 1
Total requests: 1
IP count:
::ffff:172.17.0.33: 1
$ curl ip:3000
This page was generated after talking to redis.
Application Build: 1
Total requests: 2
IP count:
::ffff:172.17.0.33: 2
以同样的方式,您可以将源容器连接到应用程序,也可以将它们连接到自己的CLI工具。
下面的命令将启动一个redis -cli工具的实例,并通过它的别名连接到redis服务器。
$ docker run -it --link redis-server:redis redis redis-cli -h redis
redis:6379> info
KEYS *
命令将输出当前存储在源redis容器中的内容。
9. Docker 网络
9.1 创建网络
第一步是使用CLI创建网络。这个网络将允许我们附加多个容器,这些容器将能够发现彼此。在本例中,我们将从创建一个后端网络开始。所有连接到我们后端的容器都将在这个网络上。
$ docker network create backend-network
89109e8de51aee15171ac6ec7257af040aecc66906777acfbbe88a715dcdb9d4
当我们启动新的容器时,我们可以使用--net
属性来分配它们应该连接到哪个网络。
$ docker run -d --name=redis --net=backend-network redis
9.2 连接网络
与使用链接不同,docker网络的行为类似于传统网络,节点可以附加/分离。
首先你会注意到Docker不再分配环境变量或更新容器的hosts文件。使用下面的两个命令,您会注意到它不再提到其他容器。
$ docker run --net=backend-network alpine env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=d566ff9c9a14
HOME=/root
$ docker run --net=backend-network alpine cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.19.0.3 97c3a236a7e6
相反,容器可以通过Docker中的嵌入式DNS服务器进行通信。这个DNS服务器通过IP 127.0.0.11
分配给所有容器,并在resolv.conf
文件中设置。
$ docker run --net=backend-network alpine cat /etc/resolv.conf
nameserver 127.0.0.11
options ndots:0
当容器试图通过众所周知的名称(如Redis)访问其他容器时,DNS服务器将返回正确的容器的IP地址。在这种情况下,Redis的完全限定名将是Redis .backend-network
。
$ docker run --net=backend-network alpine ping -c1 redis
PING redis (172.19.0.2): 56 data bytes
64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.324 ms
--- redis ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.324/0.324/0.324 ms
9.3 连接两个容器
Docker支持多个网络和容器同时连接到多个网络。
例如,让我们用Node.js应用程序创建一个单独的网络,它与我们现有的Redis实例通信。
第一个任务是以同样的方式创建一个新的网络。
$ docker network create frontend-network
37e9702dd8f695f515b988beddd1cf4d4f7b38447a4e4177d98fcf96231321b2
当使用connect命令时,可以将现有容器附加到网络上。
$ docker network connect frontend-network redis
当我们启动web服务器时,考虑到它连接到同一个网络,它将能够与我们的Redis实例通信。
$ docker run -d -p 3000:3000 --net=frontend-network katacoda/redis-node-docker-example
$ curl ping:3000
This page was generated after talking to redis.
Application Build: 1
Total requests: 1
IP count:
::ffff:172.17.0.51: 1
$ curl ping:3000
This page was generated after talking to redis.
Application Build: 1
Total requests: 2
IP count:
::ffff:172.17.0.51: 2
9.4 创建别名
使用docker网络时仍然支持链接,并提供了一种方法来定义容器名的别名。这将为容器提供一个额外的DNS条目名称和被发现的方式。当使用--link
时,嵌入式DNS将保证本地化查找结果只在使用--link
的容器上。
另一种方法是在将容器连接到网络时提供别名。
下面的命令将用db的别名将我们的Redis实例连接到前端网络。
docker network create frontend-network2
docker network connect --alias db frontend-network2 redis
当容器试图通过名称db访问服务时,他们将得到我们的Redis容器的IP地址。
$ docker run --net=frontend-network2 alpine ping -c1 db
PING db (172.21.0.2): 56 data bytes
64 bytes from 172.21.0.2: seq=0 ttl=64 time=0.170 ms
--- db ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.170/0.170/0.170 ms
9.5 断开容器连接
创建好网络后,我们可以使用CLI来探索细节。下面的命令将列出我们主机上的所有网络。
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
89109e8de51a backend-network bridge local
6fe697227a58 bridge bridge local
37e9702dd8f6 frontend-network bridge local
b0a9dbbb0bab frontend-network2 bridge local
fa054a9af353 host host local
f50397115ef2 none null local
然后,我们可以探索网络,查看连接的容器及其IP地址。
$ docker network inspect frontend-network
[
{
"Name": "frontend-network",
"Id": "37e9702dd8f695f515b988beddd1cf4d4f7b38447a4e4177d98fcf96231321b2",
"Created": "2021-09-28T12:52:03.799072129Z",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.20.0.0/16",
"Gateway": "172.20.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom":以上是关于公司要新招美女跟我学docker,你来吗?的主要内容,如果未能解决你的问题,请参考以下文章
公司新招了个人,一副毛头小子的样儿,哪想到是新一代卷王····
公司新招了个腾讯5年经验的测试员,让我见识到什么才是真正的测试天花板····