了解 Docker
看官方文档前我们得了解下docker
. Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。 . Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中, 然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。 . 容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app), 更重要的是容器性能开销极低。
docker的优势
. 解决了操作系统和软件运行环境的依赖例如: nginx 和git需要安装的 openssl 版本不同, 在同一台设备上安装会造成软件冲突. 对于开发人员来说,再也不用担心不会部署开发环境 . 开发环境,测试环境和生产环境高度一致。 . 容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统资源的利用率更高。 无论是应用执行速度、内存损耗或者文件存储速度,都要比传统虚拟机技术更高效。 因此,相比虚拟机技术,一个相同配置的主机,往往可以运行更多数量的应用。
docker的架构
docker三个基本概念
1.镜像(Image)
2.容器(Container)
镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
3.仓库(Repository)
仓库可看着一个代码控制中心,用来保存镜像。
跟着官方文档安装docker
官方文档链接
1.选择对应的docker发行版,我们直接用 CentOS 上手练习.
docker发行版
2.设置存储库
安装 yum- utils 包(提供 yum-config-manager 使用程序)并设置 稳定 存储库
yum install -y yum-utils
设置官方repo源
yum-config-manager --add-repo
安装 Docker 引擎
1.安装最新版本的 Docker Engine 和 containerd
yum install docker-ce docker-ce-cli containerd.io
不能联网的小伙伴可下载npm包, 前往 并选择您的 CentOS 版本。然后浏览 x86 _64/stable/Packages/ 并下载
yum install /path/to/package.rpm
2.启动docker
systemctl start docker ;
systemctl enable docker;
可使用systemctl status docker查看状态
3.通过运行 hello-world 映像验证 Docker Engine 是否已正确安装
“此命令下载测试映像并在容器中运行它。当容器运行时,它会打印一条消息并退出”
docker run hello-world
4.首次运行hello-world,由于本地没有该镜像,会自动下载,通过docker images可查看当前存在的镜像
docker images
5. 【可选】设置在服务器启动时启动
chkconfig docker on
卸载 Docker 引擎
一般用于删除旧版本或者重新安装时才会用到
1.卸载 Docker Engine、CLI 和 Containerd 包
yum remove docker-ce docker-ce-cli containerd.io
2. 主机上的映像、容器、卷或自定义配置文件不会自动删除。删除所有镜像、容器和卷
rm -rf /var/lib/docker
rm -rf /var/lib/containerd
学习Docker Compose
官方文档
1.官方的描述
Compose 是一个用于定义和运行的容器 Docker 应用程序的工具。借助 Compose,您可以使用 YAML 文件来配置应用程序的服务。然后,使用单个命令,从配置中创建并启动所有服务。要了解有关 Compose 的所有功能的更多信息,请参阅功能列表。
Compose 适用于所有环境:生产、登台、开发、测试以及 CI 工作流
使用 Compose 基本上是一个三步过程:
. 使用 定义您的应用程序的环境,Dockerfile以便它可以在任何地方复制。
. 定义组成您的应用程序的服务,docker-compose.yml 以便它们可以在隔离的环境中一起运行。
. 运行docker compose up和Docker compose command 启动并运行你的整个应用程序。
您也可以docker-compose up使用 docker-compose 二进制文件运行。
安装 Compose V2
1.安装并指定 复制到 $HOME/.docker/cli-plugins
mkdir -p ~/.docker/cli-plugins/
curl -SL -o ~/.docker/cli-plugins/docker-compose
chmod +x ~/.docker/cli-plugins/docker-compose
“安装得有点久 QAQ”
2.查看版本
docker compose version
官方对应V2版本的描述
新的 Compose V2 支持该compose命令作为 Docker CLI 的一部分,可作为 Docker Desktop 3.6 版本的候选版本。
Compose V2 将 compose 功能集成到 Docker 平台中,继续支持之前的大部分docker-compose功能和标志。您可以通过简单地将破折号 ( -) 替换为空格并运行docker compose, 而不是来测试 Compose V2 docker-compose。
由于 Docker Compose V2 是一个候选版本,我们建议您在生产环境中使用它之前进行广泛的测试。
生产版本建议安装稳定版本 Compose
1.安装稳定版 compose
curl -L " -s)-$(uname -m)" -o /usr/local/bin/docker-compose
2. 对 二进制 文件应用可执行权限
chmod +x /usr/local/bin/docker-compose
如果 docker-compose 安装后命令失败,请检查您的路径。您还可以在路径 /usr/bin 中创建指向或任何其他目录的符号链接。
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
3.查看版本
docker-compose --version
卸载 Compose
如果您使用 curl 以下方式安装,则直接删除compose文件即可
rm /usr/local/bin/docker-compose
入门 Compose
官方文档
1.创建项目文件夹&新增docker-compose.yml
mkdir docker_demo && cd docker_demo
touch docker-compose.yml
2.配置一个官方redis镜像用于测试
编辑文件 vi docker-compose.yml
version: ".9"
services:
my-redis:
image: " redis :alpine"
3.使用 Compose 构建并运行redis
docker-compose up
Compose 会拉取一个 Redis 镜像,为您的代码构建一个镜像,并启动您定义的服务。在这种情况下,代码会在构建时静态复制到映像中。
4.新建一个ssh console,我们通过docker images查看镜像情况
可以看到存在redis镜像, TAG版本为alpine
5.由于当前未配置挂载,停止应用程序直接在 原始终端中按 CTRL+C
也可以在第二个终端的项目目录中运行 docker- compose down
后台运行 Compose
1. 如果您想在后台运行您的服务,您可以将 -d 标志(用于“分离”模式)
docker-compose up -d
2.查看当前运行的服务
docker-compose ps
3.停止服务
docker-compose stop
4. 使用以下 down 命令关闭所有内容,完全删除容器
docker-compose down
宿主机绑定redis端口 对外开放
1.修改docker-compose.yml文件, 写入ports
当前配置宿主机的6380端口绑定到my-redis容器端口6379
version: ".9"
services:
my-redis:
image: "redis:alpine"
ports:
- ":6379"
2.运行compose
docker-compose up -d
3.查看端口绑定情况
docker ps
通过PORTS可以看到6380->6379/tcp
netstat -alpn|grep
通过netstat查看本地6380端口,也可以看到监听情况
4.使用redis客户端连接 端口为6380
添加挂载项目文件夹
volumes将主机上的项目目录(当前目录)挂载到容器/code内部,允许您即时修改代码,而无需重新构建映像
1.创建redis项目目录,可存放如redis.conf配置文件
mkdir -p conf/redis
touch conf/redis/redis.conf
2.修改docker-compose.yml文件, 设置redis配置目录到/code/
[root@iZwzf7wlklxqmxg8enulrZ conf]# cd redis/
version: ".9"
services:
my-redis:
image: "redis:alpine"
volumes:
- ./conf/redis/:/code/
ports:
- ":6379"
3.运行compose
docker-compose stop
docker-compose up -d
4.通过sh命令进入容器,查看/code是否存在redis.conf文件
通过docker-compose ps查看容器ID/NAMES
通过exec命令,进入容器终端
命令格式 docker exec -it CONTAINER ID/NAMES 执行终端
docker exec -it docker_demo_my-redis_ /bin/sh
进入/code文件夹,可以看到redis.conf文件
5.测试在容器修改redis.conf,宿主机是否同步更新
编辑 redis.conf文件,我们输入test字符串用于测试
test
此时文件大写为5kb
进入宿主机的conf/redis可以看到redis.conf也存在test字符串
配置环境变量
官方文档
1.修改docker-compose.yml文件,设置environment环境变量
我们设置一个key为MY_ENV的环境变量,值为development; LANG为zh_CN.UTF-8
version: ".9"
services:
my-redis:
image: "redis:alpine"
volumes:
- ./conf/redis/:/code/
environment:
MY_ENV: development
LANG : zh_CN.UTF-8
ports:
- ":6379"
2.运行compose
docker-compose stop
docker-compose up -d
3.通过sh命令进入容器
docker exec -it docker_demo_my-redis_ /bin/sh
通过 echo 命令可以看出,LANG和MY_ENV环境变量已写入
替换 Compose 文件中的环境变量
1.可使用当前用户环境配置变量 .bash_profile
1) 修改docker-compose.yml文件,通过${}格式读取环境变量
version: ".9"
services:
my-redis:
image: "redis:alpine"
volumes:
- ./conf/redis/:/code/
environment:
MY_ENV: ${MY_ENV}
LANG: zh_CN.UTF-
ports:
- ":6379"
2) 设置环境变量.bash_profile,写入MY_ENV
echo "export MY_ENV=development" >> ~/.bash_profile
source ~/.bash_profile
echo $MY_ENV
3) 运行compose
docker-compose stop
docker-compose up -d
4) 检查环境变量是否生效
docker exec -it docker_demo_my-redis_ echo $MY_ENV
docker exec -it docker_demo_my-redis_ echo $LANG
2.使用.env文件
1) 新增.env文件
echo "MY_ENV=test" > .env
echo " JAVA _HOME=/usr/local/java/jdk_1.8.1" >> .env
2) 我们新增JAVA_HOME环境变量,用于验证.env文件和.bash_profile环境变量的优先级
修改docker-compose.yml
version: ".9"
services:
my-redis:
image: "redis:alpine"
volumes:
- ./conf/redis/:/code/
environment:
MY_ENV: ${MY_ENV}
JAVA_HOME: ${JAVA_HOME}
LANG: zh_CN.UTF-
ports:
- ":6379"
3) 运行compose
docker-compose stop
docker-compose up -d
4) 通过condig查看 替换环境变量后的docker-compose
docker-compose config
很明显,我们写入.env的环境变量并没有覆盖.bash_profile环境变量
“官方给出答案 shell 中的值优先于 .env 文件中指定的值 ”
5) 如果我们删除.bash_profile环境变量的MY_ENV,则.env文件的环境变量不会被覆盖
3.使用–env-file指定环境文件
在实际使用中,我们可能会有多个环境,只有一个.env显然不能满足需求,可通过–env-file指定使用的.env环境文件
1) 新增.env.pro文件,用于存放生产环境参数
echo "MY_ENV=pro" > .env.pro
2) 启动compose时,指定.env.pro
docker-compose stop
docker-compose --env-file .env.pro up -d
3) 检查环境变量信息
docker exec -it docker_demo_my-redis_ /bin/sh
echo $MY_ENV
当前MY_ENV环境变量已改成pro
在 Compose 中使用配置文件
官方文档
1.配置文件profile属性官方给出的说法
1) 配置文件允许通过有选择地启用服务来针对各种用途和环境调整 Compose 应用程序模型。这是通过将每个服务分配给零个或多个配置文件来实现的。如果未分配,则始终启动该服务,但如果已分配,则仅在激活配置文件时才启动。
2) 这允许人们在单个docker-compose.yml文件中定义额外的服务,这些服务应该只在特定场景中启动,例如用于调试或开发任务。
按我理解,profiles用于给每个服务设置标签,例如 debug -用于开发调试/prod-用于生产;
profiles允许设置多个;
2.设置profiles
1) 修改docker-compose.yml, 加入nginx服务,并且设置profiles属性
version: ".9"
services:
my-redis:
image: "redis:alpine"
volumes:
- ./conf/redis/:/code/
environment:
MY_ENV: ${MY_ENV}
JAVA_HOME: ${JAVA_HOME}
LANG: zh_CN.UTF-
ports:
- ":6379"
my-nginx:
image: "nginx:latest"
profiles:
- debug
2) 启动compose,不指定profiles
docker-compose stop
docker-compose up -d
通过docker-compose可以看出,只有my-redis服务启动了
3) 启动compose,指定profiles为debug
docker-compose stop
docker-compose --profile debug up -d
通过docker-compose可以看出,my-redis和my-nginx服务都启动了
服务依赖配置
在实际场景中,我们往往依赖A服务启动后,才能启动B服务;
例如 微服务 架构中,注册中心必须优先启动,其他服务才能依次运行.
1.我们修改docker-compose.yml,新增nacos服务,修改redis依赖nacos服务
version: ".9"
services:
my-redis:
image: "redis:alpine"
volumes:
- ./conf/redis/:/code/
environment:
MY_ENV: ${MY_ENV}
JAVA_HOME: ${JAVA_HOME}
LANG: zh_CN.UTF-
ports:
- ":6379"
my-nacos:
image: 'nacos/nacos-server:latest'
profiles:
- test
my-nginx:
image: "nginx:latest"
depends_on:
- my-nacos
profiles:
- debug
2.启动compose,指定profiles为debug
docker-compose down
docker-compose --profile debug up -d
结果启动会报错,因为nacos的profiles配置为test,而且nginx依赖nacos
遇到profiles不一致,但又想都启动的情况,可以使用指定多个–profile
docker-compose --profile debug --profile test up -d
在生产中使用 Compose
1.在不同环境中,我们可以为每个环境创建不同的docker-compose.ym副本
1) 例如创建一份prod生产配置
创建docker-compose-prod.yml
touch docker-compose-prod.yml
写入服务配置
version: ".9"
services:
my-redis:
image: "redis:alpine"
volumes:
- ./conf/redis/:/code/
environment:
MY_ENV: ${MY_ENV}
JAVA_HOME: ${JAVA_HOME}
LANG: zh_CN.UTF-
ports:
- ":6379"
my-nacos:
image: 'nacos/nacos-server:latest'
2) 运行compose
docker-compose down docker-compose -f docker-compose-prod.yml up -d
通过docker-compose ps可以看出,运行了prod配置的my-nacos和my-redis
2.可以同时执行多个docker-compose.yml服务
1) 新增docker-compose-debug.yml服务
version: ".9"
services:
my-nginx:
image: "nginx:latest"
2) 运行compose
docker-compose down
docker-compose -f docker-compose-debug.yml -f docker-compose-prod.yml up -d
通过docker-compose ps 可以看出三个服务均正常运行
那么问题来了,如果有重复的配置,谁能覆盖谁? — 我们测试下
3) 修改prod配置,新增my-nginx环境变量
version: ".9"
services:
my-redis:
image: "redis:alpine"
volumes:
- ./conf/redis/:/code/
environment:
MY_ENV: ${MY_ENV}
JAVA_HOME: ${JAVA_HOME}
LANG: zh_CN.UTF-
ports:
- ":6379"
my-nacos:
image: 'nacos/nacos-server:latest'
my-nginx:
image: "nginx:latest"
environment:
MY_ENV: prod
4) 修改debug配置,增加环境变量
version: ".9"
services:
my-nginx:
image: "nginx:latest"
environment:
MY_ENV: debug
5) 启动compose
docker-compose down
docker-compose -f docker-compose-debug.yml -f docker-compose-prod.yml up -d
通过docker-compose ps 可以看出三个服务均正常运行
6) 检查my-nginx环境变量
docker exec -it docker_demo_my-nginx_ /bin/sh
echo $MY_ENV
结果MY_ENV环境变量为prod,后者覆盖前者配置
服务启动时,执行指定命令
command命令示例, 此示例最终执行command为 java -jar test.jar
command会覆盖默认的cmd命令
version: ".9"
services:
my-nginx:
image: "nginx:latest"
volumes:
- ./conf/nginx/:/code/
environment:
MY_ENV: debug
command:
- java
- -jar
- test.jar
容器启动后,执行指定名
可通过entrypoint指定需要执行的命令或脚本
version: ''
services:
db:
image: 'mysql:.7'
container_name: mysql
environment:
- TZ=Asia/Shanghai
- LANG=en_US.UTF-
ports:
- ':3307'
entrypoint: /mysql.sh
设置容器名
1.细心的同学应该发现,服务名名格式目前是{当前项目名}_{服务ID}_1
通过配置container_name可指定名称
修改docker-compose.xml文件
version: ".9"
services:
my-redis:
image: "redis:alpine"
container_name: mredis
volumes:
- ./conf/redis/:/code/
environment:
MY_ENV: ${MY_ENV}
JAVA_HOME: ${JAVA_HOME}
LANG: zh_CN.UTF-
ports:
- ":6379"
my-nacos:
image: 'nacos/nacos-server:latest'
container_name: mnacos
my-nginx:
image: "nginx:latest"
container_name: mnginx
2.运行compose
docker-compose down docker-compose up -d
通过docker-compose ps 可以看出服务名已变更为我们指定的名称
docker网络
官方文档
默认情况下,Compose为您的应用程序设置单个 网络 。服务的每个容器都加入默认网络,并且 可以 被该网络上的其他容器 访问 ,并且可以在与容器名称相同的主机名上被它们 发现 。
1.Docker有以下网络类型
bridge:多由于独立container之间的通信
host: 直接使用宿主机的网络,端口也使用宿主机的
overlay:当有多个docker主机时,跨主机的container通信
macvlan:每个container都有一个虚拟的MAC地址
none: 禁用网络
2. Docker在默认情况下,分别会建立一个bridge、一个host和一个none的网络
3.默认的bridge网络与自建bridge网络有以下区别:
1. 端口不会自行发布,必须使用-p参数才能为外界访问,而使用自建的bridge网络时,container的端口可直接被相同网络下的其他container访问。
2. container之间的如果需要通过名字访问,需要–link参数,而如果使用自建的bridge网络,container之间可以通过名字互访。
3. 更多的区别官方文档 #differences-between-user-defined-bridges-and-the-default-bridge
创建自定义网络并使用
1.创建自定义网络
创建名为my_network 的bridge网络,指定子网段172.20.0.0
docker network create --driver=bridge --subnet=.20.0.0/16 my_network
通过docker network ls 可以看到 已创建my_network网络
2.修改docker-compose.yml配置
version: ".9"
services:
my-nginx:
image: "nginx:latest"
volumes:
- ./conf/nginx/:/code/
environment:
MY_ENV: debug
command:
- java
- -jar
- test.jar
networks:
my_network:
external: true
name: my_network
3.运行compose
docker-compose down docker-compose up -d
4.测试容器间的网络
docker exec -it mnacos sh
通过ping mnginx 和 ping mredis 可以看出,容器内部可以使用别名进行通信
使用重启策略
官方文档
Docker 建议您使用重启策略,并避免使用进程管理器来启动容器。
docker-compose.yml也可配置restart参数
version: ".9"
services:
my-redis:
image: "redis:alpine"
container_name: mredis
ports:
- ":6379"
networks:
- my_network
restart: always
制作自己的镜像
1.注册 Docker Hub账号
2.创建公共资源库(个人账号私有库只能一个,练习就用公开的)
3.从官方找一个纯净的CentOS系统
docker search centos
也可以从Docker Hub官网搜索
4.拉取镜像
docker pull centos
5.查看镜像信息
docker images
6.创建并进入容器
格式:docker run -dit –name=容器名 镜像 id /bin/bash
docker run -dit --name=test_centos centos /bin/bash
通过docker ps可查看已经启动容器 名为test_centos
7.进入容器
docker exec -it test_centos /bin/bash
创建一个readme.md文件用于测试
echo "hello world" > readme.md
8.将容器制作成镜像
-m 来指定提交的说明信息,跟我们使用的版本控制工具一样;-a 可以指定更新的用户信息;之后是用来创建镜像的容器的 ID;最后指定目标镜像的仓库名和 tag 信息
docker commit -m 'test' -a 'me' test_centos/panda_cn:v1
通过docker images可看到已存在镜像并且版本为v1
9.将制作好的镜像推送到Docker Hub
docker push/panda_cn:v1
如果提示“ denied: requested access to the resource is denied ”
需要登录Docker HUB账号才行
docker login -u 你的docker hub账号
用DockerFile制作镜像
使用 docker commit 扩展一个镜像比较简单,但是不方便在一个团队中分享;
我们可以使用DockerFile构建镜像
1.创建DockerFile模板
touch Dockerfile
2.写入内容
FROM: 使用基础镜像
MAINTAINER: 作者
RUN: 开头的指令会在创建中运行,比如安装一个软件包
CMD: 执行命令
# base image
FROM centos
# MAINTAINER
MAINTAINER test@.com
# install telnet
RUN yum install telnet -y
CMD echo "Hello world! This is my first Docker image."
3.生成镜像
格式 docker build -t <your_username>/my-private-repo .
注意命令最后还有个 “ . ” 表示DockerFile位置处于当前路径
docker build -t/panda_cn:V2 .
通过docker ps查看镜像信息
4.测试镜像
格式 docker run <your_username>/my-private-repo
docker run/panda_cn:V2
4.推送镜像至Docker Hub
格式 docker push <your_username>/my-private-repo
docker push/panda_cn:V2
至此,docker你学废了吗
学得差不多了,我们来总结下
1.docker的镜像分层
2.镜像与容器的联系
3.镜像存储核心技术:写时复制(COW)
引入写时复制(copy-on-write),需要修改文件操作时,会先从镜像里把要写的文件复制到自己的文件系统(容器的读写层)中进行修改。源镜像层中的文件不会发生变化。