文章目录
一、什么是容器(container)?
1.概念
沙盒进程,与主机上的所有其他进程隔离,这种隔离利用了Linux的内核特性,Docker把这些变得易于使用。
2.总结
- 是镜像的运行时实例。可以利用DOCKERAPI或CLI创建、启动、停止、移除或删除。
- 可在本地、虚拟机上运行或发布到云上。
- 具有可移植性(可以在任何操作系统上运行)。
- 容器是彼此独立的,运行各自的软件、二进制和配置。
二、什么是容器镜像(container image)?
1.概念
当运行一个容器,它会使用一个被隔离的文件系统。这个自定义的文件系统就是容器镜像提供的。因为镜像包含容器的文件系统,所以它必须包含运行一个应用的所有必须的东西 - 所有依赖、配置、脚本、二进制等等。镜像同样包含一些容器的其他配置,比如环境变量,默认的运行命令和其他的元数据。
三、Docker 架构
- Docker使用client-server架构,即Docker client 与Docker daemon交互,Docker daemon做一些比较重的工作,比如建立、运行、分发Docker容器。
- Docker client可以和Docker daemon可以运行在同一个系统,或也可以Docker client与远程Docker daemon交互。
- Docker client与daemon交互使用基于UNIX sockets或网络接口的REST API。
- 另一种Docker client是Docker Compose,它可以让你使用由大量容器组成的应用。
四、Docker概览
- Docker是一个提供应用开发、运输和运行的开放平台。Docker使应。用与基础设施能够分离开来,这样可以做到快速部署。
- 使用Docker,能够像管理应用一样管理基础设施。
- 利用Docker方法的优势,可以做到快速代码运输、测试和开发,这会极大的减少代码开发与生产部署的时间。
五、Dockerfile知识汇总
1. 概念
Dockerfile是一个简单的基于文本的指令脚本,被用来创建一个容器镜像。
2.代码示例与解读
# syntax=docker/dockerfile:1
FROM node:12-alpine
RUN apk add --no-cache python2 g++ make
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
docker build -t getting-started .
- 此命令使用上述的Dockerfile文件去创建一个新的容器镜像。
- 你会注意到 ,当命令 运行时,有很多 layers 被下载,是因为我们指示这次构建我们想从node:12-alpine这个镜像开始,但是我们的机子上并没有此镜像,因此需要下载。
- 当镜像被下载完毕后,我们copy到我们机子并使用yarn命令去安装我们应用的依赖。
- CMD指令指示了当我们启动容器时的默认命令。
- -t参数标识我们的镜像,这是镜像的最终名称,因为我们将镜像命名为getting-started,所以我们可以在运行容器的时候引用该镜像。
- docker buidler命名的最后的.告诉Docker应该在当前文件下找Dockerfile文件。
六、容器命令积累
- Docker 启动命令* -> docker run -dp 3000:3000 getting-started //-d 后台启动; -p 端口映射。
- Docker 镜像构建命令 -> docker build -t getting-started . // -t 标识镜像tags; . 告诉Docker从当前文件下找Dockerfile文件。
- Docker 查看日志命令 -> docker logs-f <container’id> 。
- Docker 运行开发模式容器命令 -> docker run -dp 3000:3000 -w /app -v “$(pwd):/app” node:12-alpine sh -c “yarn install && yarn run dev” // 12节有详细解释。
- Docker 创建网络 -> docker network create todo-app 。
- Docker 连接mysql -> docker exec -it mysql -u root -p 。
- Docker 指定网络运行容器 -> docker run -it --network todo-app nicolaka/netshoot // nicolaka/netshoot 附带了许多工具,这些工具对于故障排除或调试网络问题非常有用。
- Docker docker-compose启动 -> docker-compose up -d // 使用docker-compose up命令启动应用程序堆栈。我们将添加-d标志来在后台运行一切。
- Docker 监听指定容器的日志在多容器应用环境下 -> docker-compose logs -f [service-name] 。
- Docker Compose 运行命令 -> docker-compose up -d 。
- Docker Compose 查看容器日志 -> docker-compose logs -f 。
- 进入dokcer redis -> docker exec -it [容器id] redis-cli
- redis容器挂在目录并使用lus脚本 ->docker run
-d --privileged=true
-p 6379:6379
-v /docker/redis/conf/redis.conf:/etc/redis/redis.conf
-v /docker/redis/data:/data
–name redistest2 redis:4.0 redis-server /etc/redis/redis.conf --appendonly yes
redis-cli --eval /data/gupao.sh
七、使用Docker CLI Remove容器
1.步骤
docker ps: 获得容器ID
docker stop
docker rm
2.Note
以上命令可以合并为docker rm -f
八、分享应用
1.术语解读
- Docker registry: 默认的注册中心是 Docker Hub。
- Docker ID: Docker账号给予你访问世界上最大的容器镜像库与社区—Docker Hub。
- Docker Repository: 要想push镜像,需要现有一个仓库。
2. 推送镜像
- docker tag 【image-name】 YOUR-USER-NAME/【image-name】
- docker login -u YOUR-USER-NAME
- docker push YOUR-USER-NAME/【image-name】:【tagName】
九、在全新的实例上运行镜像
1.测试网站
https://labs.play-with-docker.com/
2.使用说明
点击右侧 ADD NEW INSTANCE在终端中输入运行的命令:
docker run -dp 3000:3000 YOUR-USER-NAME/getting-started
十、容器的文件系统
1.概念
当运行容器时,他会使用其镜像不同的层作为其文件系统,每一个容器都会获得其独立的“暂存空间”用来创建/修改/移除文件,任何的改变都不会影响其他的容器,即使他们使用同一个镜像。
十一、容器数据卷
1.卷的作用
卷提供了将容器的特定文件系统路径连接回主机的能力。如果容器中的一个目录被挂载,那么在主机上也会看到该目录中的更改。如果我们在容器重启时挂载相同的目录,我们将看到相同的文件。
2.卷的类型
- named volume: 类似一个存储数据的桶,Docker持有并维护它在磁盘上的物理位置,仅需要数据卷的名称,每次使用数据卷的时候,Docker将会提供正确的数据。
- bind mounts: 可以控制主机上的准确挂载点。我们可以使用它来持久化数据,但它通常用于向容器中提供额外的数据。在处理应用程序时,我们可以使用绑定挂载将源代码挂载到容器中,让它看到代码更改、响应,并让我们立即看到更改。
3.卷类型的快速对比
**绑定挂载**和**命名卷**是Docker引擎附带的两种主要卷类型。不过,还可以使用其他卷驱动程序来支持其他用例(SFTP、Ceph、NetApp、S3等)。
Named Volumes | Bind Mounts | |
---|---|---|
Host Location | Docker选择 | 你掌控 |
Mount Example(using -v) | my-volume:/usr/local/data | /path/to/data:/usr/local/data |
用容器内容填充新卷 | 是 | 否 |
支持数据卷驱动程序 | 是 | 否 |
4.数据持久化
a.关于数据持久化的理论分析:
假设数据库是一个文件而已,如果我们可以把那个文件持久化到宿主机上,并使之可以为下一个容器所使用,那么它将从上一个容器结束的地方开始。
通过创建一个数据卷并把它挂载到数据存储的文件,我们就可以持久化数据。比如我们这个例子:当容器写入todo.db文件时,它将被持久化到卷中的主机上。
b.关于使用数据卷实现数据持久化的实践:
-
创建数据卷 -> docker volume create todo.db
-
删除之前未使用数据卷的Docker容器
-
重启容器,并使用一个-v参数指定一个具体的数据卷重启容器,我们将使用指定的卷并将其挂载到/etc/todos,这将捕获在该路径上创建的所有文件
-> docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started
十二、启动开发模式容器
1.前提条件
为了运行我们的容器来支持一个开发环境的工作流程,我们需要保证:
- 把我们的源码挂载进容器。
- 安装所有依赖项,包括“dev”依赖项。
- 启动nodemon来观察文件系统的变化。(对于基于node的应用程序,nodemon是一个很好的工具,可以监视文件更改,然后重新启动应用程序。在大多数其他语言和框架中都有等价的工具。)
2. 关于启动开发模式容器的实践
-
确保没有任何该镜像之前的容器在运行。
-
运行一下命令:
-
查看日志 -> docker logs-f <container’id>
docker run -dp 3000:3000 -w /app // 设置工作目录,或者说,当前命令从那个文件运行 -v "$(pwd):/app" // 绑定挂载主机上的一个文件路径到容器中的 /app文件 Note: $(pwd)命令会运行失败,需要给定一个主机上的绝对路径,且格式是 这样的 G:demo/app -> /g/demo/app node:12-alpine sh -c "yarn install && yarn run dev" // 安装所有依赖并运行, alpine没有bash命令
3.使用绑定挂载的优势
在本地开发设置中,使用绑定安装非常常见。这样做的好处是,开发机器不需要安装所有的构建工具和环境。使用一个docker run命令,dev环境就可以pull到所有所需并完美运行。
十三、多容器应用
1.架构设计的原因
一般来说容器只应做一件事情,并做好,且一个容器运行多个进程更复杂的操作,还有很多其他的原因,所以我们的应用应当这样设计:
2.容器网络
默认情况下,容器是独立运行,并不会知道同机器上其他进程或其他容器的的 任何情况,那容器间该怎样通信?答案就是网络,但你也没必要成为一名网络工程师,记住一条原则就够了: 如果容器在一个网络他们就可以交互,如果不是就不能。
3.将一个容器放在网络上的两种方式
有两种方法将一个容器放在网络上:
- 在开始时分配它。
- 连接一个现有的容器。
4.启动MySQL
- 创建网络 -> docker network create todo-app
- 启动一个MySQL容器并将其连接到网络 -> docker run -d --network todo-app --network-alias mysql -v todo-mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=secret -e MYSQL_DATABASE=todos mysql:5.7
- 连接mysql验证其是否启动 -> docker exec -it mysql -u root -p
- 连接上以后输入 SHOW DATABASES;
5.连接MySQL
mysql已经启动并正常运行,那么我们如何才能使用其工作,或者说我们的app如何能连接到该容器,首先我们要弄清楚如何找到mysql容器:
- 使用容器 nicolaka/netshoot,确保它连接的是相同的网络 -> docker run -it --network todo-app nicolaka/netshoot在 nicolaka/netshoot
- 容器内,使用dig命令,它是一个非常有用的DNS工具,我们将用它查找hostname为mysql的IP地址 -> dig mysql
- 虽然mysql通常不是一个有效的主机名,但Docker能够将其解析为具有网络别名的容器的IP地址(还记得我们之前使用的——network-alias标志吗?)这意味着…我们的应用程序只需要简单地连接到一个名为mysql的主机,它将与数据库对话!
6.运行使用mysql的app
1.mysql设置
todo应用程序支持设置一些环境变量来指定MySQL连接设置 :
- MYSQL_HOST - the hostname for the running
- MySQL serverMYSQL_USER - the username to use for the connection
- MYSQL_PASSWORD - the password to use for the connection
- MYSQL_DB - the database to use once connected
注意 :***虽然使用env vars设置连接设置通常可以用于开发,但在生产环境中运行应用程序时非常不建议这样做。**你的应用程序需要知道如何查找变量并获取文件内容。[比较难先不做探究]*
2.关于运行使用mysql的app的实践:
a.运行命令:
docker run -dp 3000:3000
-w /app -v "$(pwd):/app"
--network todo-app
-e MYSQL_HOST=mysql
-e MYSQL_USER=root
-e MYSQL_PASSWORD=secret
-e MYSQL_DB=todos
node:12-alpine
sh -c "yarn install && yarn run dev"
b.查看日志 -> docker logs -f
c.进入mysql查看数据 -> docker exec -it mysql -p todos
十四、使用Docker Compose
1.Docker Compose的作用
- Dcoker Compose 是用来帮助定义和分享多容器应用,在Docker Compose帮助下,我们可以用一个Yaml文件来定义我们的服务,仅用一个命令就可以代替十三节这些繁杂的命令。
- 使用Compose的最大优点是,您可以在文件中定义应用程序堆栈,将其保存在项目repo的根目录(现在它是版本控制的),并很容易让其他人对您的项目做出贡献。有人只需要复制你的repo并启动compose应用程序。事实上,你可能会看到GitHub/GitLab上有相当多的项目正在做这一点。
2.安装Docker Compose
Dock Desktop已经自动安装Docker Compose,如果你是用的Linux主机,那么你需要手动安装Docker Compose: https://docs.docker.com/compose/install
3.创建Compose文件
version: "3.7"
services:
app:
image: node:12-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
working_dir: /app
volumes:
- /g/Demo/getting-started/app:/app
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: secret
MYSQL_DB: todos
mysql:
image: mysql:5.7
volumes:
- todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: todos
volumes:
todo-mysql-data:
4.运行应用栈
- 运行命令 -> docker-compose up -d
- 查看容器日志 docker-compose logs -f
十五、关于镜像构建的最佳实践
1.关于层的一个定律
一旦一个layer发生了变化,那么它所有的下流的层都将被重新创建。
2.延展出关于镜像最佳构建的一个特别有趣的问题
首先,还记得我们的Dockerfile文件嘛,用你刚学到的去看看它的镜像历史输出吧
# syntax=docker/dockerfile:1
FROM node:12-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
您可能还记得,当我们更改映像时,必须重新安装yarn依赖项。有办法解决这个问题吗?每次构建时都围绕着相同的依赖关系交付没有多大意义,对吧?
3.使用Layer caching
1.首先我们来看一张图:
请运用【十五.1】的定律来尝试理解改图左侧和右侧的Dockerfile文件的不同
2.创建忽略文件: .dockerignore
3.重新构建镜像 -> docker build -t getting-started . // 注意你会看到很多层被重构了,这是因为我们的Dockerfile文件改变了很多
4.多阶段构建
1.顾名思义,多阶段构建,指使用多个阶段构建镜像,是一个非常有用的帮助。
- 将构建时依赖项与运行时依赖项分开
- 通过只发送应用程序需要运行的内容来减少整体图像大小
- 多级构建还通过将构建时依赖关系与运行时依赖关系分离,帮助我们减少整体图像大小并提高最终容器的安全性。
2.两个例子与解析
a.Maven/Tomcat example:
当构建一个基于java的应用,JKD仅在编译源码成字节码时被需要,可是,JDK在产品中并不需要,同样,你可能使用Maven或Gradle来构建APP,它们在我们的最终镜像中同样不需要,那么,多阶段构建就可以帮助你解决这个问题。
在下面这个例子中,我们使用一个阶段“build”来使用Maven来执行真正的Java build。在第二个阶段(from FROM tomcat),我们把阶段“build”复制到文件中。这些也不是最终镜像所需要的。
b.React example:
我们构建React Applications,我们需要Node环境来编译Js代码等等到H5页面,在某种情况下,我们不需要把Node环境放到我们的产品中,为什么不把静态资源放到Nginx中交付呢?
下面的代码的意思是,我们使用node:12来执行build然后把输出复制到Nginx容器中。
c. getting-started’s Dockerfile: