虚拟化 - Docker
- 概念
- 容器技术
- 是一种虚拟化方案
- 是基于Linux内核的虚拟化技术,因此也被称为基于操作系统的虚拟化,因此只能运行相同或相似内核的操作系统。虚拟机是操作系统级别的资源隔离,而容器本质上是进程级的资源隔离。
- 依赖于Linux内核特性(Namespace和Cgroups(Control Group)),因此只能运行Linux系统
- Namespaces命名空间
- 编程语言的命名空间是为了封装、代码隔离
- 操作系统的命名空间是为了系统资源的隔离,如进程、网络、文件系统等
- 5种命名空间
- PID(Process ID)进程隔离
- NET(Network)管理网络接口
- IPC(InterProcess Communication)管理跨进程通信的访问
- MNT(Mount)管理挂载点
- UTS(Unix Timesharing System)隔离内核和版本标识
- Control groups控制组
- Linux提供的一种可以限制、记录、隔离进程组所使用的资源的技术
- 用来分配资源
- 来源于Google
- 起始于Linux kernel 2.6.24 @ 2007
- 是容器技术的基础
- 功能
- 资源限制,比如内容超了再申请则抛出Out of memory
- 优先级设定,比如哪些进程组可以使用更大的CPU等资源
- 资源计量,尤其用于计费功能
- 资源控制,可以将进程组挂起和恢复
- 两者的作用
- 文件系统隔离。每个容器都有自己的root文件系统
- 进程隔离。每个容器都运行在自己的进程环境中
- 网络隔离。容器间的虚拟网络接口和IP地址都是分开的
- 资源隔离和分组。使用cgroups将CPU和内存之类的资源独立分配给每个Docker容器
- Namespaces命名空间
- 容器化技术很早就有了,但是复杂、不易安装使用和管理,而Docker改变了这些,能够把开发的应用程序自动部署到测试、生产容器的引擎。是一个应用程序部署引擎,目标是提供一个轻量、快速的环境能够快速运行开发者的程序,并能部署到测试、生产环境。
- 容器技术
- 与虚拟机的对比
- Docker并没有和虚拟机一样利用一个独立的Guest OS执行环境的隔离,它利用的是目前当前Linux内核本身支持的容器方式,实现了资源和环境的隔离,简单来说,Docker就是利用Namespace 实现了系统环境的隔离,利用了cgroup实现了资源的限制,利用镜像实例实现跟环境的隔离。
- 隔离级别不同导致性能、隔离性不同。虚拟机从操作系统级别进行隔离,有独立的Guest OS,隔离得更彻底;而Docker只是基于Linux内核的容器技术进行应用级别的隔离。
- 优点
- 不需要包含操作系统,因此空间占用小
- 目标
- 提供简单轻量的建模方式
- Docker容器大多不到一秒就能运行起来。由于去除了管理程序的开销,因此拥有更高的性能,同时同一台宿主机中可以运行更多的容器,更充分的利用系统资源。
- 职责的逻辑分离
- 开发人员只需要关心容器中运行的应用程序,而运维人员只需要关心容器的管理
- Docker的目的就是加强开发人员写代码的环境和要部署的环境之间的一致性
- 快速高效的开发声明周期
- Docker缩短了从开发、测试、部署、上线运行的周期,让应用程序具备可移植性,在容器中开发,以容器的形式进行交付,让开发、测试、部署使用相同的环境,避免了额外的部署、调试的开销。
- 鼓励使用面向服务的架构
- Docker鼓励单个容器只运行一个应用程序,这样就形成了一个分布式的应用程序模型,这种模型下所有的应用程序和服务都可以表现为一系列内部互联的容器,让分布式应用程序的部署和调试都变得简单。避免了在同一服务器(容器)中部署多个服务或应用程序导致互相之间的影响,容易定位问题。
- 提供简单轻量的建模方式
- 使用场景
- 进行容器开发、测试、部署服务
- 创建隔离的运行环境
- 搭建本地/测试环境
- 构建多用户的平台即服务(PaaS)基础设施
- 提供软件即服务(SaaS)应用程序
- 高性能、超大规模的宿主机部署。AWS、Azure都支持Docker,OpenStack、CloudFoundry也都基于Docker提供了应用部署的功能。
- 组成
- Docker Client客户端
- Docker是C/S架构的程序。
- Docker Daemon守护进程
- Docker Image镜像
- 容器的基石,容器基于镜像启动,镜像相当于容器的源代码,保存了用于启动容器的各种条件。
- 是一个层叠的只读文件系统。
- 最底层是bootfs引导系统,用户一般不会和它有交互。启动后,容器被加载到内存中,而引导系统将会被卸载。
- rootfs,root文件系统,永远只读状态
- 联合加载(union mount)
- 一次同时加载多个文件系统,外面看起来只有一个文件系统
- add emacs
- add Apache
- 可以一直累加,称为父镜像、基础镜像等
- Docker Container容器
- 通过镜像启动
- 用docker run命令以某个镜像创建并启动容器后,镜像和容器就没有关系了,后面对容器也只需要进行stop、start等操作,不再需要执行run命令了。
- 启动和执行阶段
- 写时复制(copy on write)
- 在前面的文件系统上再加一个可写层,初始为空,当你修改了文件时,将该文件从下层复制到可写层(写时复制),该只读文件仍存在但被可写层的复制服务覆盖
- 为container设置环境变量时,如果想放在启动配置文件中,而不是每次启动后都要用export设置一遍,那么环境变量就要设置在/root/.bashrc中,Linux中常用的全局的/etc/profile中,否则每次exit或者restart后都要source /etc/profile,restart容器也没用(可能是docker或者说Linux容器的实现原理导致?)。
- 其实可以发现,source /etc/profile后,用户名就变了。不过也无法解释为什么/etc/profile这种全局的也不会在启动时执行。可能/etc/profile是当用户第一次登录时,该文件被执行。而docker的start和attach,并不是一般的登录?
- 通过镜像启动
- Docker Registry仓库
- 用仓库来保存用户创建的镜像(一般本地都有一个隐藏的私有的仓库供用户使用?)
- 分为私有和共有(官方提供了Docker Hub,已经有了丰富的镜像,可以节省自己构建镜像的时间)
- Docker Client客户端
- Docker Hub
- Docker CE和Docker EE
- Docker从17.03开始分为企业版与社区版,社区版并非阉割版,而是改了个名称;企业版则提供了一些收费的高级特性。
- Docker Enterprise
- Docker Engine
- 安装
- Docker Desktop (for windows and mac)
- Docker Desktop
- 其实是利用Windows的Hyper-V功能建了一个默认启动的占用2GB内存的linux虚拟机来跑容器(也可以选使用Windows容器,就不知道是怎样的实现了?)
- 由于本质上用的是Windows的Hyper-V,所以在Windows的Hyper-V中右侧Actions中有一部分专门可以对DockerDesktopVM进行一些配置。
- docker容器与宿主机之间的网络通信
- 由于本质上用的是Windows的Hyper-V,所以docker容器与宿主机之间的网络通信本质上是基于Hyper-V的网络设置的(Hyper-V中的switch交换机即网卡设置)。
- 设置(任务栏单击图标选Settings)
- 网络(Network)
- 代理(Proxies)
- 如果在公司内部网络等需要设置代理的地方,就要在任务栏右击弹出窗的settings下的Proxies中设置代理(有的话还要包括端口号)。Apply后会卡住重启。
- 修改系统环境变量、cmd中设置的http_proxy和https_proxy是没用的,这只会影响cmd环境,并不能影响docker运行时的网络请求。
- 重启启动时,可能报错“VIRTUALIZATION MUST BE ENABLED”
- https://docs.docker.com/docker-for-windows/troubleshoot/#virtualization-must-be-enabled
- https://github.com/docker/for-win/issues/74
- 需要在BIOS中开启CPU的虚拟化功能,可以在任务管理器的性能面板的CPU部分看到是否开启成功
- 共享盘(Shared Drives)
- 注意
- 安装时有可能卡主,可以关掉重新装
- Linux
- yum remove docker
- yum install -y yum-utils device-mapper-persistent-data lvm2
- yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
- yum install docker-ce docker-ce-cli containerd.io
- systemctl start docker
- docker version
- docker image ls
- docker container run hello-world
- docker run hello-world
- Docker Desktop (for windows and mac)
- 工具
- Kitematic
- 可以用于管理docker中的元素,如同时管理多个container
- Kitematic
- 使用
- 获取/制作镜像
- 可以从Docker Hub等地方下载镜像:可以通过命令Docker pull xxx下载
- 有时会报错说manifest not found,这是因为需要指定tag,如docker pull xxx:1.7.1
- 可以自己制作一个镜像
- 可以从Docker Hub等地方下载镜像:可以通过命令Docker pull xxx下载
- 使用镜像创建/运行容器
- 获取/制作镜像
- 命令
- Docker 常用命令总结
- Docker 命令大全
- 服务
- 启动服务
- systemctl start docker
- service docker start
- 重启服务
- systemctl restart docker
- 重启后容器都会被停掉,需要重新启动
- systemctl restart docker
- 启动服务
- Image(镜像)相关
- 查看有哪些镜像:docker images或docker image ls -a或docker image list
- 创建镜像
- 从已经创建的容器中更新镜像,并且提交这个镜像
- 使用Dockerfile指令文件来创建一个新的镜像
- docker build -t 目标镜像名 .
- . :Dockerfile 文件所在目录,可以指定Dockerfile 的绝对路径
- docker build -t 目标镜像名 .
- 删除镜像
- docker rmi 镜像名称
- 有的需要加上-f参数强制删除
- 仓库
- 在仓库中搜索镜像:docker search 镜像名称关键字
- 从仓库中下载镜像
- docker pull 镜像名称
- docker pull 镜像名称:tag
- 保存镜像到仓库中:docker push 镜像名称
- 好像不能在命令中查看某个镜像的所有tag,只能去dockerHub上去看,或者写脚本调其接口去查tags
- 编译镜像
- docker build
- -t xxx
- 想要生成的镜像的标签信息
- -f
- Dockerfile所在的目录
- 也可以直接在命令最后加一个.,代表就用当前目录的Dockerfile
- —network=host
- 后续RUN命令的网络模式
- 仅仅是设置编译镜像时使用的网络类型,和最终run时的网络没关系,docker run也可以设置网络类型。
- 默认使用Bridge网络,即和宿主机在同一内网里。
- 也可以指定为使用host网络,即没有自己的网卡,直接使用宿主机的网络(也同时使用Docker Desktop中的proxy和执行命令的cod 中的proxy配置?)
- -t xxx
- Dockfile
- 指令
- ENV
- ENV xxx yyy
- 设置环境变量
- 给后续RUN命令使用
- 容器运行起来以后,也可以获得这些环境变量
- 可以用来设置网络代理:
- ENV HTTP_PROXY=“http://127.0.0.1:3128”
- ENV HTTPS_PROXY=“http://127.0.0.1:3128”
- COPY
- COPY src dst
- 从宿主机往镜像中拷贝文件或文件夹
- src就是宿主机上基于编译目录的相对路径
- dst就是编译出的镜像中的目录,不存在时会自动创建
- RUN
- 执行命令
- 多行命令的话,除最后一行外的每行用” &&\”结尾
- ENV
- 指令
- docker build
- Container(容器)相关
- 查询
- 查看有哪些容器:docker ps -a
- 查看有哪些运行的容器:docker ps
- 获取容器/镜像的元数据:docker inspect 容器ID
- 使用docker run创建并启动/运行容器(基于image镜像):
- -i, --interactive
- Keep STDIN open even if not attached
- -d, --detach
- Run container in background and print container ID
- 在大部分的场景下,我们希望 docker 的服务是在后台运行的,我们可以过 -d 指定容器的运行模式。
- 在后台运行容器,并打印出容器的ID(只有以d参数运行后,才支持使用stop/start/restart命令对指定ID的容器进行操作)
- --name string
- Assign a name to the container
- 一般就第一次以某个image启动container时,需要指定name
- 如果pull的时候带了tag,那么以此image启动container时,image名称也要加上tag。
- docker run -itd —name kibana kibana:7.9.1 /bin/bash
- 示例
- docker run -it 镜像名 /bin/bash
- docker run -itd --name ubuntu-test ubuntu /bin/bash
- docker run -idtv D:\docker_share:/home/docker_share --name ubuntu-test ubuntu /bin/bash
- -p,—publish list
- Publish a container’s port(s) to the host
- 把宿主机某端口映射到docker容器的某端口
- 如-p hostport:containerport,-p ip:hostport:containerport
- -P参数是随机进行端口映射,而-p是可以指定端口号
- 如果要映射多个端口,每个映射关系都要用一个单独的-p来进行设置
- 查看端口占用及端口映射
- 可以使用docker port containername port来查看该容器是否有该端口的public映射,或者docker port containername来查看所有的映射
- 可以使用docker ps命令就可以看到,有一个PORTS列,会列出所有的端口占用和映射
- 即使不在docker run时指定端口映射,也可能会有默认的端口占用(或映射?),比如cents的PORTS列默认是空的,而pgadmin4的PORTS列是有80和443端口占用信息的
- 常用于允许外网访问
- 设置了端口映射才有可能让外网访问到
- 此外还有一个前提是宿主机到docker这一段也要通
- 如果是在一台Linux机器上直接装的docker
- vim /usr/lib/systemd/system/docker.service
- 修改ExecStart这行
- 想设置n个端口映射,就设置n个-H tcp://0.0.0.0:port
- ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
- 重新加载配置文件
- systemctl daemon-reload
- 重启服务
- systemctl restart docker.service
- systemctl restart docker
- 查看端口是否开启
- netstat -nptl
- netstat -an | grep port
- ps aux | grep docked
- 直接curl看是否生效
- 如果用的是ufw
- sudo ufw allow from 172.18.0.0/24
- sudo ufw allow from 172.18.0.0/24 to any port 9200
- 如果用的是iptables
- iptables —append INPUT —protocol tcp —src 172.18.0.0/24 —jump DROP
- 如果是在一台Linux机器上直接装的docker
- 有时docker端口映射或启动容器时报错
- docker服务启动时定义的自定义链DOCKER由于 centos7 firewall 被清掉
- firewall的底层是使用iptables进行数据过滤,建立在iptables之上,这可能会与 Docker 产生冲突。
- 当 firewalld 启动或者重启的时候,将会从 iptables 中移除 DOCKER 的规则,从而影响了 Docker 的正常工作。
- 当你使用的是 Systemd 的时候, firewalld 会在 Docker 之前启动,但是如果你在 Docker 启动之后再启动 或者重启 firewalld ,你就需要重启 Docker 进程了。
- 重启docker服务及可重新生成自定义链DOCKER
- 需要重启doclear服务:systemctl restart docker
- -e,—env list
- 设置环境变量,比如容器中的服务启动所需的环境变量配置
- 和设置端口映射-p一样,每个环境变量都要有一个-e来分别设置
- 必须在设置-itd和—name之前先设置环境变量
- 用单引号’’或双引号“”来封装每个环境变量都可以
- 比如启动pgadmin4的容器,需要设置run时的环境变量:docker run -p 90:90 -e ‘PGADMIN_DEFAULT_EMAIL=xxx.com’ -e ‘PGADMIN_DEFAULT_PASSWORD=123456’ -it’d —name pgadmin4 page/pgadmin4
- -t, --tty
- Allocate a pseudo-TTY
- 为什么不加会报错?/bin/bash: line 1: $'\r': command not found
- -v, --volume list
- Bind mount a volume
- firewall-rules-for-shared-drives
- 和宿主机之间设置共享文件夹(只能在run的时候指定,创建并启动后就不能再添加了?)
- 如果用的是Windows上的Docker Desktop
- 这个共享文件夹功能基于Docker Desktop的Shared Drives功能的,因此需要先把Windows上该共享文件夹所在盘的共享打开。而打开Shared Drives功能又需要打开防火墙设置。
- 可以直接建立Windows上的文件夹到container中文件夹的映射和共享(但是需要防火墙通过),不需要麻烦的先从Windows共享到Linux虚拟机然后再到container。
- -i, --interactive
- 进入容器:docker attach 容器ID 或者 docker exec -it 容器ID /bin/bash
- 退出容器
- 退出容器,并且关闭容器: exit
- 退出容器,而不关闭容器: ctrl+p+q,ctrl+q、ctrl+q+p(英文)、ctrl+c再ctrl+z
- 停止容器:docker stop 容器 ID
- 重启容器:docker restart 容器ID
- 启动容器后进入交互式:docker start -i 5c6ce895b979
- 和docker run的区别是,docker run一般只运行一次,然后容器就已经创建了;如果容器因为stop或exit等操作导致停止,那么只需要使用docker start即可重新启动该容器,不需要使用docker run命令来重建容器。
- 删除容器:docker rm -f 容器ID
- 查看容器日志
- 即使容器启动失败了,也可以看到错误日志
- docker logs 容器名
- 导出和导入容器快照
- docker export 1e560fca3906 > ubuntu.tar
- cat docker/ubuntu.tar | docker import - test/ubuntu:v1动/
- 查询
- 其他
- cp
- Copy files/folders between a container and the local filesystem
- 不仅可以在container和宿主机之间拷贝文件,也可以在container内拷贝文件(不同container间也可以?)
- 即使是Windows上的Docker Desktop,也可以直接用这个命令把Windows上的文件拷贝到container中,而不需要管中间的linux虚拟机(DockerDesktopVM)。
- docker cp D:\files ubuntu-test:/home/files
- cp