docker学习
docker介绍
Docker 是一种运行于 Linux 和 Windows 上的软件,用于创建、管理和编排容器。
Docker 公司起初是一家名为 dotCloud 的平台即服务(Platform-as-a-Service, PaaS)提供商。
底层技术上,dotCloud 平台利用了 Linux 容器技术。为了方便创建和管理这些容器,dotCloud 开发了一套内部工具,之后被命名为“Docker”。Docker就是这样诞生的!
2013年,dotCloud 的 PaaS 业务并不景气,公司需要寻求新的突破。于是他们聘请了 Ben Golub 作为新的 CEO,将公司重命名为“Docker”,放弃dotCloud PaaS 平台,怀揣着“将 Docker 和容器技术推向全世界”的使命,开启了一段新的征程。
作用
Docker 是一个可以将应用程序及其依赖打包到几乎可以在任何服务器上运行的容器的工具。Docker能极大简化环境运维过程。 Docker容器最重要价值在于提供一整套平台无关的标准化技术,简化服务的部署、升级、维护,只要把需要运维的各种服务打包成标准的集装箱,就可以在任何能运行docker的环境下跑起来,达到开箱即用的效果。
docker容器和虚拟机区别
区别:
虚拟机实现资源的隔离的方式是利用独立的Guest OS,以及利用Hypervisor虚拟化CPU、内存、IO等设备来实现的。
Docker用docker Engine层取代了虚拟机的Guest层和Hypervisor层,利用的是目前当前Linux内核本身支持的容器方式,实现了资源和环境的隔离,简单来说,Docker就是利用Namespace 实现了系统环境的隔离,利用了cgroup实现了资源的限制,利用镜像实例实现跟环境的隔离。
好处:
Docker有着比虚拟机更少的抽象层。由于Docker不需要Hypervisor实现硬件资源的虚拟化,所以运行在Docker容器上的程序,直接使用的都是实际物理机的硬件资源。因此在
cpu、内存、利用率
上,Docker将会在效率上具有更大的优势。Docker直接利用虚拟机机的系统内核,避免了虚拟机启动时所需要的系统引导时间和操作系统运行的资源消耗,利用Docker能够在几秒钟之内启动大量的容器,是虚拟机无法办到的。
快速启动低资源消耗
的优点,使Docker在弹性云平台自动运维系统方面具有很好的应用场景。
安装
-
卸载旧版本
sudo yum remove docker \ docker-client \ docker-client-latest \ docker-common \ docker-latest \ docker-latest-logrotate \ docker-logrotate \ docker-engine
-
安装需要的安装包
sudo yum install -y yum-utils # 设置国内镜像仓库 sudo yum-config-manager \ --add-repo \ https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
-
更新yum软件包索引
yum makecache fast
-
安装docker相关的 docker-ce 社区版 而ee是企业版
sudo yum install docker-ce docker-ce-cli containerd.io
-
启动docker
sudo systemctl start docker
-
使用docker version查看是否按照成功
docker version
-
测试
docker run hello-world
基本命令
帮助命令
docker version #显示docker的版本信息。
docker info #显示docker的系统信息,包括镜像和容器的数量
docker 命令 --help #帮助命令
镜像命令
docker images #查看所有本地主机上的镜像或者docker image ls
docker search #搜索镜像
#列出收藏数不小于3000的镜像
docker search mysql -f stars=3000
docker pull #下载镜像 docker image pull
docker rmi #删除镜像 docker image rm
#传递参数删除所有的镜像
docker rmi -f $(docker images -aq)
docker save 容器id -o newname.tar #保存已有的镜像
docker load < tar_name #载入镜像文件到本地
#把容器保存为镜像,-m表示message,-a作者信息,-p提交时暂停容器运行。
docker commit -m "this is a test" -a "username" -p 容器id 镜像名:版本号
下载镜像的过程
指定了tomcat的版本 “8-jdk8-corretto”,不指定版本则下载最新版本“latest”
search命令的结果
参数说明:
NAME:
镜像仓库源的名称
DESCRIPTION:
镜像的描述
stars:
类似 Github 里面的 star,表示点赞、喜欢的意思。
OFFICIAL:
是否 docker 官方发布
AUTOMATED:
自动构建。
容器命令
docker run 镜像id #新建容器并启动
#--name="Name" ;-d 后台方式运行
# -it 使用交互方式运行,进入容器查看内容;
# -p 指定容器的端口 -p 8080(宿主机):8080(容器);
# -P(大写) 随机指定端口
docker ps #列出所有运行的容器;-a所有包括已经停止的容器;-q列出容器id
docker ps -a #列出所有包括已经停止的容器
docker rm 容器id #删除指定容器
docker rm $(docker ps -aq) #删除所有容器
docker start 容器id #启动容器
docker restart 容器id #重启容器
docker stop 容器id #停止当前正在运行的容器
docker kill 容器id #强制停止当前容器
常用其他命令
docker logs [OPTIONS] 容器id
# 查看容器mynginx从2016年7月1日后的最新10条日志
docker logs --since="2016-07-01" --tail=10 mynginx
# 查看镜像的元数据
docker inspect 容器id
# 进入容器内部
docker exec -it 容器id bash
docker attach 容器id
docker attach --sig-proxy=false 容器id
#docker exec #进入当前容器后开启一个新的终端,可以在里面操作。(常用)
#docker attach #进入容器正在执行的终端,退出会停止容器,ctrl+p+q
镜像原理
Image layering
docker image history getting-started
docker image history --no-trunc getting-started #--no-trunc查看完整的命令
写时复制
Docker 镜像是由文件系统叠加而成。
最底端是一个引导文件系统,即 bootfs。当一个容器启动后,引导文件系统会随即从内存被卸载。
第二层是 root 文件系统 rootfs。rootfs 可以是一种或多种操作系统, 如 Debian 或 Ubuntu;在 Docker 中,root 文件系统永远只能是只读状态,并且 Docker 利用联合文件系统又会在 rootfs上加载更多的
只读
文件系统。Docker 将此称为镜像。一个镜像可以放到另一个镜像的顶部。位于下面的镜像称为父镜像(Parent Image),而最底部的镜像称为基础镜像(Base Image)。最后,当从一个镜像启动容器时,Docker 会在该镜像之上加载一个读写文件系统。这才是我们在容器中执行程序所在的地方。
当 Docker 第一次启动一个容器时,
初始的读写层是空的,当文件系统发生变化时,这些变化都会应用到这一层之上
。比如,如果想修改一个文件,这个文件首先会从该读写层下面的只读层复制到该读写层。由此,该文件的只读版本依然存在于只读层,只是被读写层的该文件副本所隐藏。该机制则被称之为
写时复制(Copy on write)
。
最大的一个好处就是
共享资源
比如:有多个镜像都从相同的base镜像构建而来,那么宿主机只需在磁盘上保存一份base镜像,同时内存中也只需加载一份base镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
联合文件系统
此时镜像对外表现为6个文件
此时镜像对外表现也为6个文件:对文件5进行修改,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中,并保证多镜像层对外展示为统一的文件系统
数据管理
数据卷
volume是存在一个或多个容器中的特定文件或文件夹,这个目录能够独立于联合文件系统的形式在宿主机中存在,并为数据的共享与持久提供便利。
[root@yd02 _data]# docker volume --help
Usage: docker volume COMMAND
Manage volumes
Commands:
create 创建一个数据卷
inspect 展示数据卷的详情
ls 列出数据卷的列表
prune 删除本地所有未在使用的数据卷
rm 删除指定数据卷
#创建一个名叫mydata的数据卷,这时查看/var/lib/docker/volumes/路径下,会发现所创建的数据卷位置
docker volume create mydata
#创建容器的时候绑定数据卷
docker run -d -v mydata:/test tomcat:8-jdk8-corretto
#在使用-v时,如果用的是名字,docker会自动增加volume
docker run -d -v mydata2:/test tomcat:8-jdk8-corretto
数据卷容器
如果用户需要在多个容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。数据卷容器也是一个容器,但是它的目的是专门提供数据卷给其他容器挂载。使用
--volumes-from container_NAME
实现。
#多个容器使用相同数据卷
docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:8.0.25
docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:8.0.25
挂载主机目录
#直接挂载宿主机目录
docker run -it -v /宿主机绝对路径目录:/容器内目录 镜像名
小结
容器停止、删除后数据卷内容也不会被删除,向
/data
中写入的信息都不会记录进容器存储层,从而保证了容器存储层的无状态化。
# 三种挂载: 匿名挂载、具名挂载、指定路径挂载
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载 docker volume ls是查看不到的
容器互联
link互联
容器的互联是一种让多个容器中应用进行快速交互的方式,它会在源和接收容器之间建立连接关系,接收容器可以通过容器名快速访问到源容器,而不用指定具体的IP地址。使用—link参数可以让容器之间安全地进行交互。
[root@master ~]#docker run -d --link mysql01 nginx
此时nginx容器已经和db容器建立互联关系:—link参数的格式为:—link name:alias,其中name是要连接的容器名称,alias是这个连接的别名。Docker相当于在两个互联的容器之间创建了一个虚拟通道,而不用映射它们的端口到宿主机上。在启动db容器的时候并没有使用-p或者-P参数,从而避免了暴露数据库服务端口到外部网络上。
此时nginx容器能ping通mysql01容器,但mysql01不能ping通nginx容器。
已经不再推荐使用
网络
建议大家将容器加入自定义的 Docker 网络来连接多个容器,而不是使用
--link
参数
docker network create -d bridge my-net
docker run -it -d --rm --name mysql01 --network my-net -P -e MYSQL_ROOT_PASSWORD=123456 mysql
docker run -it -d --rm --name nginx01 --network my-net nginx
加入到同一个网络中的容器,相互之间都是可以ping通的。
问题(解决): bash: ping: command not found
1)这时候需要敲:apt-get update,这个命令的作用是:同步 /etc/apt/sources.list 和 /etc/apt/sources.list.d 中列出的源的索引,这样才能获取到最新的软件包。
2)等更新完毕以后再敲命令:apt-get install iputils-ping命令即可。
构建镜像Dockerfile
Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。
构建镜像命令:
docker build -t yourimagename:tag .
dockerfile指令
FROM # from:基础镜像,一切从这里开始构建
MAINTAINER # maintainer:镜像是谁写的, 姓名+邮箱
RUN # run:镜像构建的时候需要运行的命令
ADD # 复制指定内容到容器的目的地址,可以是相对路径、url、tar文件(会自动解压)
WORKDIR # workdir:镜像的工作目录
VOLUME # volume:挂载的目录
EXPOSE # expose:保留端口配置
CMD # cmd:指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT # entrypoint:指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD # onbuild:当构建一个被继承DockerFile这个时候就会运行onbuild的指令,触发指令
COPY # copy:类似ADD,将我们文件拷贝到镜像中,当使用本地目录为源目录时,推荐使用
ENV # env:构建的时候设置环境变量!
# 简单示例
[root@yd02 dockertest]# cat Dockerfile
FROM busybox
COPY /hello /
RUN cat /hello
构建镜像可能报错:
[root@yd02 dockertest2]# docker build -t helloapp:v1 .
Sending build context to Docker daemon 4.096kB
Step 1/3 : FROM busybox
latest: Pulling from library/busybox
Get https://registry-1.docker.io/v2/: dial tcp: lookup registry-1.docker.io on 10.0.2.3:53: server misbehaving
解决:
修改虚拟机中/etc/resolv.conf
修改前
nameserver 10.0.2.3
修改后
nameserver 8.8.8.8
构建镜像执行过程:
[root@yd02 dockertest2]# docker build -t helloapp:v1 .
Sending build context to Docker daemon 4.096kB
Step 1/3 : FROM busybox
latest: Pulling from library/busybox
b71f96345d44: Pull complete
Digest: sha256:930490f97e5b921535c153e0e7110d251134cc4b72bbb8133c6a5065cc68580d
Status: Downloaded newer image for busybox:latest
---> 69593048aa3a
Step 2/3 : COPY /hello /
---> 63e93099c1a6
Step 3/3 : RUN cat /hello
---> Running in 9c662c7a5117
hello
Removing intermediate container 9c662c7a5117
---> 3a8afcaa6771
减小镜像/容器大小
docker是C/S架构,客户端发送文件到docker引擎执行命令,尽量减少不必要的文件,减小镜像大小。
Sending build context to Docker daemon 4.096kB
-
.dockerignore
要排除与构建无关的文件,使用.dockerignore文件。类似.gitignore文件
# comment*/temp**/*/temp*temp?
-
通过&&连接多个命令减少层数
-
将构建过程分为多个阶段,每个阶段都可以指定一个基础镜像,这样在一个Dockerfile就能将多个镜像的特性同时用到,例如:先用maven镜像构建java工程,再把构建结果和jre合成,就做成了一个可以直接运行java工程镜像了;
-
每个容器负责单一职责,相互依赖的容器用网络通信
FROM java:8
LABEL MAINTAINER=“hebaulida”
ADD /target/dockerdemo-0.0.1-SNAPSHOT.jar demo.jar
EXPOSE 8080
ENTRYPOINT [“java”,”-jar”,“demo.jar”]
Docker Compose
Docker的最佳实践是一个容器只运行一个进程,因此要运行多个组件则必须运行多个容器。通过 Compose,就可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。
- 查看版本
docker-compose version
- 安装
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
- 安装成功
[root@yd02 /]# docker-compose version
docker-compose version 1.29.2, build 5becea4c
docker-py version: 5.0.0
CPython version: 3.7.10
OpenSSL version: OpenSSL 1.1.0l 10 Sep 2019
- 卸载
sudo rm /usr/local/bin/docker-compose
示例
- spring boot项目中,配置jdbc示例
spring:
datasource:
driver: com.mysql.jdbc.Driver
url: jdbc:mysql://${MYSQL_HOST:127.0.0.1}:3306/dockertest?useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
username: ${MYSQL_USER:root}
password: ${MYSQL_PASSWORD:123456}
- docker-compose.yml示例
version: "3.7"
services:
app:
image: java:8
ports:
- 8080:8080
restart: "always"
volumes:
- ./dockerdemo-0.0.1-SNAPSHOT.jar:/dockerdemo-0.0.1-SNAPSHOT.jar
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: 123456
MYSQL_DB: dockertest
entrypoint: java -jar dockerdemo-0.0.1-SNAPSHOT.jar
mysql:
image: mysql:latest
ports:
- 3306:3306
volumes:
- todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: dockertest
volumes:
todo-mysql-data:
- 运行
docker-compose up -d
By default, Docker Compose automatically creates a network specifically for the application stack
Docker Compose自动为应用栈里的应用创建了网络,不再需要手动创建。
- 查看日志
docker-compose logs -f
- 停止
docker-compose down
完整的项目地址
https://gitee.com/hebaulida/dockerdemo
容器的核心技术
- cgroup
- namespace
- rootfs之联合文件系统
Cgroup
docker本身提供了一些参数进行对资源的限制,其原理是通过cgroups来做限制的。Linux Cgroups的全称是Linux Control Group。它最主要的作⽤,就是限制⼀个进程组能够使⽤的资源上限,包括CPU、内存、磁盘、⽹络带宽等等。Linux Cgroups就是Linux内核中⽤来为进程设置资源限制的⼀个重要功能。
Cgroup实现了一个通用的进程分组的框架,不同资源的具体管理是由各个Cgroup子系统实现的。
CPU:使用调度程序为cgroup任务提供 CPU 的访问。
cpuacct:产生cgroup任务的 CPU 资源报告。
cpuset:如果是多核心的CPU,这个子系统会为cgroup任务分配单的CPU和内存。
devices:允许或拒绝cgroup任务对设备的访问。
freezer:暂停和恢复cgroup任务。
memory:设置每个cgroup 的内存限制以及产生内存资源报告。
net_cls:标记每个网络包以供 cgroup方便使用。
ns:命名空间子系统。
perf event:增加了对每个group的监测跟踪的能力,可以监测属于某个特定的group 的所有线程以及运行在特定CPU上的线程。
Namespace
Namespace是将内核的全局资源做封装,使得每个Namespace都有一份独立的资源,因此不同的进程在各自的Namespace内对同一种资源的使用不会互相打扰。
linux内核提拱了6种namespace隔离的系统调用,如下图所示,但是真正的容器还需要处理许多其他工作。
UTS:隔离主机名或域名
IPC:隔离信号量、消息队列和共享内存
PID: 隔离进程编号
Network: 隔离网络设备、网络战、端口等
Mount: 隔离挂载点(文件系统)
User: 隔离用户和用户组
Kubernetes
Kubernetes(k8s)是用于编排容器化应用程序的云原生系统。最初由Google创建,如今由Cloud Native Computing Foundation(CNCF)维护更新。Kubernetes是最受欢迎的集群管理的解决方案之一,可实现应用程序顺畅的自动化部署,可操作性和可伸缩性。
简而言之,如果你的应用程序可以容器化(例如,借助Docker),它们绝对应该由Kubernetes运行和管理。在K8s的支持下,你可以大大提高本地或云托管基础架构的利用率,所有计算资源都可以在多个应用程序之间动态而合理地共享。
利用 Kubernetes,您能够达成以下目标:
- 跨多台主机进行容器编排。
- 更加充分地利用硬件,最大程度获取运行企业应用所需的资源。
- 有效管控应用部署和更新,并实现自动化操作。
- 挂载和增加存储,用于运行有状态的应用。
- 快速、按需扩展容器化应用及其资源。
- 对服务进行声明式管理,保证所部署的应用始终按照部署的方式运行。
- 利用自动布局、自动重启、自动复制以及自动扩展功能,对应用实施状况检查和自我修复。
参考