Docker入门
Docker
概述
- Docker是开发、部署、发布和运行应用服务的开放平台。
- 部署、测试、开发应用更快快捷。
- Docker提供了打包和运行服务的独立的环境——Container.
- Container是轻量级的,且包含运行应用服务的所有依赖。因此,可在不同机器上保持一致性。
优势:
- 快速的,一致的应用服务交付:容器利于持续集成和持续交付工作流程。(continuous integration and continuous delivery (CI/CD))
- 敏捷部署和扩展。(高可移植性,轻量级)
- 同样硬件下提供更多的负载。
体系结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8YMiNa4F-1655775416318)(…/…/image/article/docker/docker_architecture.svg)]
Docker使用的是client-server架构。client 与Docker守护进程间(daemon)进行通信,完成编译、运行、分配Docker容器。客户端可在本地运行,也可以远程链接至服务端的守护进程。客户端与服务端通过基于Unix的Socker或网络接口的 REST API完成通信。Docker Compose 是一个客户端,允许使用由一组容器组成的应用程序。例如常用的:docker-compose up , docker-compose down。
The Docker daemon
Docker守护进程监听Docker API请求。包括,镜像、容器、网络、卷等。守护进程间也可通信。
The Docker client
大多数Docker用户使用Docker的主要方式。例如, docker run
Docker Desktop
面向Mac和Windows环境的应用,提供构建和分享容器化应用和微服务。包含Docker守护进程、客户端、Docker Compose、K8s、证书帮助等。
Docker Registries
一个关于Docker 镜像、容器、网络、卷、插件以及其他对象的概要说明。docker pull, docker push, docker run等命令与此相关。
Docker对象
Images 镜像
镜像是一个只读模板,用于创建Docker容器。通常,一个镜像依赖与另一个镜像。通过创建Dockerfile、定义创建镜像的一些步骤,完成创建。Dockerfile中的每一个指令都会在镜像中创建一层(layer)。当修改Dockerfile并重建镜像时,只有那想相关的层(layer)会被重建。这事镜像轻量化、更快捷。
Containers 容器
容器是镜像的一个可执行实例。同时可基于容器当前状态创建一个新的镜像。
Docker 下载
入门教程
- 编译和运行一个镜像至容器;
- 通过Docker Hub分享镜像
- 多容器应用间的依赖
- 通过Docker compose运行应用
开始
- 运行getting-started镜像。若本地无该镜像,docker会自动运行docker pull命令进行下载。
docker run -d -p 80:80 docker/getting-started
-d : 使用detached模型运行,即后台运行
-p 80:80 : 将host的80端口映射到容器的80端口
本地打开127.0.0.1:80 可看到Getting Started网页。
- Docker Dashboard
Windows Docker Dashboard stopping 问题解决:https://blog.youkuaiyun.com/qq_39611230/article/details/108625840
需要更新WSL 组件
Docker Dashboard在Windows下安装后,暂时无法管理linux服务器上的远程Docker容器。Ubuntu中需要22.04版本以上才可安装Docker Dashboard。因此,暂不整理Docker Dashboard相关内容。
- 什么是容器
容器就是运行在主机上的一个与其他进程相互独立的沙盒进程。其原理是利用linux的核命名空间和控制组,Docker使这些能力与方法使用的更便捷。
- 是镜像的一个可执行实例
- 能够在本地机器、虚拟机、或云端运行
- 可移植
- 什么是容器镜像
当运行一个容器的时候,容器具有独立的文件系统。这个文件系统是由容器镜像提供的。容器镜像包含运行容器的所有内容。
示例应用
编译一个应用的容器镜像
需要创建一个Dockerfile.Dockerfile是一个基于文本的指令脚本,用于创建容器镜像。
- 在项目文件夹下创建一个Dockerfile,与packages.json在同一个文件夹下。
# 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"]
EXPOSE 3000
- 使用docker build命令编译镜像。注意,后面有URL路径,此为Dockerfile路径,下述命令值为当前路径。
docker build -t getting-started .
build过程:发送编译上下文至Docker daemon;执行Dockerfile中的指令;拉取所需镜像;添加apk;设置工作路径;yarn安装package.json中的包;运行前端。
执行过程中下来了很多曾,这是因为从node:12-alpine镜像开始。因为本地无该镜像,所以下载。下载完成后通过yarn安装依赖。通过CMD命令运行特殊的命令。
Dockerfile中 RUN 与 CMD 的区别:RUN是docker在创建镜像时执行的指令,每个RUN命令会创建镜像的新层,便于后续回滚。一个Dockerfile最多只会有一个CMD,该命令也会运行指令,但不会创建新曾。因此常用CMD执行一个脚本文件(例如sh文件),用于执行多条指令。
- 开始运行应用容器
一般通过docker run指令。首先使用docker run指令利用先前的容器名称 getting-started启动刚刚创建的镜像;其中-d表示后台运行;-p表示将容器端口映射到主机。其中左侧为主机端口,右侧为容器中的服务端口,下述:3000是容器中的服务端口,3001是映射到主机的端口。
docker run -dp 3001:3000 getting-started
更新应用
在修改完代码后不可直接用docker run 编译镜像。因为此时已有在运行中的同名称镜像容器。需要先删除老容器后,再编译新镜像容器。
删除容器
- docker ps 查看容器id
- docker stop container-id
- docker rm container-id
重新编译运行
- docker build -t getting-started
- docker run -dp 3000:3000 getting-started
分享应用
通过Docker Hub的服务可以上传和下载镜像。
创建仓库
- 登录Docker Hub
- 进入Repositories模块,点击Create Repossitory
- 输入名称及其他配置。
上传镜像
- 使用docker login -u YOUR_USER_NAME登录
- 使用的 docker tag为镜像添加tag
docker tag getting-started YOUR_USER_NAME/getting-started:v1.0
- 使用docker push YOUR_USER_NAME/getting-started:v1.0 上传镜像。
持久化存储
容器运行期间对容器内部的存储内容修改,并不会保存下来。为了持久化保存,需要使用容器卷支持。卷提供了容器访问本地文件系统的能力。
命名卷
docker自行管理命名卷的物理位置,使用时只需记住卷的名称。
- 通过 docker volume create 创建
docker volumne create todo-db
- 删除todo应用的容器(未挂载)
- 启动容器,并添加-v标签,挂在一个特殊的卷。利用上面创建的命名卷,挂在到/etc/todos路径,这样该路径下的所有文件就会保存在命名卷中。下次启动后仍然保留。
docker run -dp 3001:3000 -v todo-db:/etc/todos getting-started
- 添加记录,删除容器,重启容器,可看到持久化保持的内容。
命名卷的详细保存地址:可通过 docker volume inspect NAME 查询。
绑定挂载
使用绑定挂在,我们能够控制挂载在主机的位置。在开发应用时,我们通过绑定挂载,将代码挂载到容器中,就能直接看到代码改变,响应。
绑定挂载和命名卷是docker的两种主要卷。其他驱动也支持:SFTP ,Ceph等。
- 关闭运行中的getting-started容器
- 在app目录下运行如下命令
docker run -dp 3001:3000 \
-w /app -v "$(pwd):/app" \
node:12-alpine \
sh -c "yarn install && yarn run dev"
- -dp 3000:3000 端口映射
- -w /app 设置工作目录
- -v “$(pwd):/app” 将当前路径挂载至容器的/app路径下。相当与 COPY . .
- node:12-alpine 用于运行的镜像
- sh -c “yarn install && yarn run dev” 在容器中运行指令。不可用bash,用sh.
- 使用docker log查看系统打印log,可看到上述命令的执行过程信息
docker log -f <container-id>
此时修改前端应用文件,可看到nodejs重启信息,并且todo应用已改变。
多容器应用
每一个容器应该仅负责一个事情,且做好。容器间通过网络完成通信。例如两个容器,一个Todo App, 一个Mysql.
容器网络
默认情况下,容器是独立运行的,不知道任何其他进程或容器。容器间通过网络完成通信。
启动Mysql
有两种方式将容器添加至网络:1)作为一个启动器;2)链接一个现有的网络。以下是先创建网络,然后将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
-v挂载了命名卷,用于MySQL存储数据。
- 为了确认MySQL容器正常运行,可链接确认。
docker exec -it <mysql-container-id> mysql -u root -p
密码是步骤2中设置的 secret。
连接MySQL数据库
首先介绍一个 nicolaka/netshoot容器,包含了大量游泳的排查错误和debug的工具。
- 启动nicolaka/netshoot容器,确认连接了同一个网络。
docker run -it --network todo-app nicolaka/netshoot
- 在容器中使用dig命令,查看DNS信息,查看mysql的IP地址。
dig mysql
其中ANSWER SETCION中就是mysql的IP.虽然mysql不是一个有效的hostname,利用上面步骤的 --network-alias 标签,Docker能够将其关联到容器的IP。这是及其方便的。
在应用中使用MYSQL
使用数据库链接参数创建MySQL链接:MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD,MYSQL_DB等。 通过设置环境变量,设置数据库连接参数。通过_FILE后缀的文件保存变量。
在MySQL 8.0以上吧本,需要执行以下命令:
ALTER USER 'root' IDENTIFIED WITH mysql_native_password BY 'secret';
flush privileges;
使用以下命令配置环境变量,启动todo-app。在这里直接使用mysql作为MYSQL_HOST,而不需要使用上述dig mysql命令查询到的IP地址。
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"
使用Docker Compose
Docker Compose是用于定义和分享多容器应用的工具。通过创建一个YAML文件定义服务,单条命令即可完成所有操作。
创建 Compose 文件
- 在应用项目的根目录,创建 docker-compose.yml文件
- 在compose文件中,需要以定义版本号为开始。通常情况下,最好是最新支持的版本。
- 然后,我们需要在文件中定义一系列我们想要运行的服务(容器)
version: "3.7"
services:
定义应用服务
回顾之前我们运行服务所运行的代码,代码中包括运行容器,端口映射,卷挂载、环境变量,运行命令等:
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"
- 首先,我们需要定义服务的入口和容器的镜像。服务的名称可以任意取。名称将会自动成为网络别名,用于Mysql服务。
version: "3.7"
services:
app:
image: node:12-alpine
- 进入容器(服务)后运行的命令(command参数)没有安放顺序要求。添加command
version: "3.7"
services:
app:
image: node:12-alpine
command: sh -c "yarn install && yarn run dev"
- 添加端口映射
version: "3.7"
services:
app:
image: node:12-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
- 添加工作目录,绑定挂载。
version: "3.7"
services:
app:
image: node:12-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
working_dir: /app
volumes:
- ./:/app
- 最后,添加环境变量参数。其中MYSQL_HOST: mysql,就是用别名访问其他容器中的服务。
version: "3.7"
services:
app:
image: node:12-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
working_dir: /app
volumes:
- ./:/app
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: secret
MYSQL_DB: todos
- 添加MYSQL容器。命名卷需要在Compose中volumes中记录。相当与运行:docker volume create todo-db
version: "2.2"
services:
app:
image: node:12-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
working_dir: /app
volumes:
- ./:/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:
version 参考表格。根据docker-compose version 查看docker-compose 版本进行填写。当前我的docker-compose为1.17.1,因此version需要填写 2.2
运行应用程序栈
- 通过docker ps确认当前无其他人应用容器在运行中。
- 运行命令,启动应用。-d 表示后台运行。
docker-compose up -d
- 通过 docker-compose logs -f 命令可查看没一个服务的日是信息。-f表示 follows,将实时打印日志信息。
- docker-compose down可停止容器运行。并会停止容器网络。
默认情况下,compose文件中配置的命名卷在 docker-compose down后不会删除。如果需要删除卷,则需要添加 --volumes标签。
镜像编译最好实践
安全扫描
编译一个镜像的时候,最好使用docker scn扫描安全隐患。使用前需要使用docker scan --login进行登录。
镜像层
通过docker image history可查看用于创建镜像每一层的命令。例如查看getting-started镜像
docker image history getting-started
可添加 --no-trunc 获取 折叠的信息(trunc - truncated - untruncated)
层缓存
当package.json修改后,进需要重新创建yarn以来层。
- 首先复制package.json。安装依赖,然后将所有的依赖拷贝进去。
# syntax=docker/dockerfile:1
FROM node:12-alpine
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --production
COPY . .
CMD ["node", "src/index.js"]
- 在Dockerfile同级目录创建.dockerignore文件.该文件是选择性的仅复制镜像相关文件的简单方法。此时应在第二个Copy中省略node_modules文件夹,否则可能会覆盖RUN步骤中创建的文件。
node_modules
Ubuntu 18.04安装Docker Dashboard
- Set up the repository
- 更新apt包
sudo apt-get update
sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
- 添加GPG key
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
- 添加仓库
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
-
下载deb包 link
-
安装依赖
Docker Dashboard 需要init-system-tool 版本大于1.4.通过去ubuntu网站查询:
系统 | init-system-tool 版本 |
---|---|
Ubuntu 18.04 | 1.51 |
Ubuntu 20.04 | 1.57 |
因此手动下载1.57 版本的init-system-tool安装。
下载链接
然后安装下载的deb包:
sudo apt-get install ./init-system-helpers_1.57_all.deb
- 安装下载的Docker Dashboard 包
sudo apt-get install ./docker-desktop
- 启动 Docker Desktop
方式1: 找到图标进行启动(启动失败)
方式2: (启动失败)
systemctl --user start docker-desktop
- 停止 Docker Desktop
systemctl --user stop docker-desktop