(一)定义与介绍
前言:与虚拟机技术比较:
- 虚拟机(VM):在docker容器技术出现之前使用的是虚拟机技术,将一台物理机虚拟化为多台机器,可搭载不同的操作系统。但每一个虚拟机系统的消耗较大,都需安装一个完整的内核,存储空间占用也多。且系统镜像也不支持版本控制。
- Docker容器技术:docker的一大特点就是简单轻便,物理机(宿主机)只需要安装docker环境,拉取image镜像,则可以通过该镜像创建一个或多个系统实例(Docker称为容器,容器间相互隔离互不影响),且image镜像与虚拟机的系统镜像相比十分小。除此之外,镜像支持版本控制,Docker可以将容器进行commit提交形成一个新的镜像,可push到远端仓库,私人备份或公有到image仓库中。对于项目开发而言,idea可以配置dockerfile实现Java项目的自动化部署。
4大概念:容器(Container),镜像(Images),仓库(Repository),宿主机(物理机)
- 仓库Repository:可指定配置源,是镜像存储的地方,可从此处拉取镜像(pull),或者将本地的镜像进行提交(push)
- 镜像Image:系统或环境的镜像文件,可由其创建并运行(run)出容器实例(container)。镜像可从仓库拉取(pull)获得,或者从现有容器commit提交得到一份新的镜像Image
- 容器Container:由镜像创建的容器实例,初始状态下各个容器实例环境相同,互不影响。容器分为两个状态:运行和停止
- 宿主机(物理机):即就是运行docker环境的这台物理机
从公有仓库拉取的镜像可以进行自定义化,然后发布到公有仓库,或是自己的私有仓库上。
同一份镜像可以产生多个容器(实例),且这些容器初始环境完全相同,且互不影响,相互隔离(文件,ip等,进程)
(二)Docker环境配置
镜像源指定:为了下载更快,可指定为阿里云(将会影响docker search的结果和docker pull的速度)
阿里源Docker服务网站:阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台
"registry-mirrors": [
"https://8rzbqaxd.mirror.aliyuncs.com"
],
- Windows下直接安装Docker Desktop即可
注意:
由于win10新版本提供了wsl2版的Linux,即Windows自带一个Linux内核,若Docker开启了wsl2的支持,则高级配置不会展示出:CPU,内存,磁盘,容器磁盘镜像目录等配置项。
Resources-Advance选项卡指定容器的配置,以及生成容器Container的磁盘镜像位置vhdx
Resources-File Sharing选项卡指定共享文件夹,即将宿主机(物理机)的某些目录用来挂载到容器中,可供容器使用
在Windows下的docker提供了两种container模式,可通过右键进行切换:但优先选择LinuxContainer
- LinuxContainer:可运行基于Linux内核和Windows内核的容器(运用Hyper-V技术)
- WindowsConainer:仅可运行基于Windows内核的容器
Image镜像的下载目录在windows平台下不方便配置,因为在LinuxContainer模式下,镜像Image文件都是下载到一个虚拟的Linux目录中的(通过docker info命令可查),若为WindowsContainer模式,则可以配置。
- Linux Ubuntu(18.04)下:
#若存在老版本先卸载之前的
sudo apt-get remove docker docker-engine docker.io containerd runc
#更新源
sudo apt-get update
#安装curl工具
sudo apt-get install curl
#添加docker的GPG密钥
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
#验证密钥
sudo apt-key fingerprint 0EBFCD88
#安装添加源工具
sudo apt install software-properties-common
#指定仓库
sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
#再次更新源
sudo apt-get update
#安装docker-ce(社区版),cli客户端,以及解耦api
sudo apt-get install docker-ce docker-ce-cli containerd.io
验证docker环境:
docker -v
#或者
systemctl status docker
Ubuntu版的docker配置:
全局配置文件在:/etc/default/docker
sudo vim /etc/default/docker
修改镜像下载目录与修改容器磁盘镜像文件目录
默认配置可以通过docker info命令查看
该文件夹包含了下载的image和container文件夹
若需要修改,则要修改:/etc/systemd/system/multi-user.target.wants/docker.service文件
sudo vim /etc/systemd/system/multi-user.target.wants/docker.service
修改为其他位置即可
配置阿里源:创建/etc/docker/daemon.json,并写入以下内容:然后重启服务systemctl restart docker
{
"registry-mirrors": [
"https://8rzbqaxd.mirror.aliyuncs.com"
]
}
(三)基本Docker命令
- 镜像Images相关 (镜像名要求全小写)【一般为docker image xxx】
#获取当前所配置的源下,与输入的关键字相关的可提供下载的镜像(存放在远端的仓库)
docker search <关键字>
#按版本筛选(加标签)
docker search <关键字>:<tag>
例:docker search centos,docker search ubuntu:18.04
其中offical代表官方,automated代表自动构建产生的镜像
注意:官方镜像系统内容很少,有时缺少基本工具,如:ifconfig,ping,sudo之类,需要运行容器后自己安装
#拉取镜像
docker image pull <imageName/imageID>
#拉取镜像(指定版本),需到其官网查看他在docker hub上该版本的tag
docker image pull <imageName>:<tag>
#将镜像推送到远端仓库(imageName要求包含远端仓库地址)
docker image push <imageName>:<tag>
#查看所有已有的镜像
docker image ls
#创建容器并运行(最基础的)(可指定tag)
docker run --name <newContainerName> <imageName>:<tag>
#删除已有镜像(tag不为latest时,需要指定tag)【确保无本镜像创建的container】
docker image rm <imageName>
#镜像重命名
#此时会生成一个id相同的新镜像,手动删除之前不要的即可(可指定tag)
docker image tag <imageName> <newImageName>
#查看镜像详细信息(可指定tag)
docker image inspect <imageName>
- 容器Container相关【一般为docker container xxx】
#查看容器列表(正在运行的)
docker container ls
#查看容器列表(所有的)
docker container ls -a
#运行已存在的容器
docker container start <containerName>
#停止某个运行的容器
docker container stop <containerName>
#重启某个容器
docker container restart <containerName>
#删除某个容器(确保该容器已停止运行)
docker container rm <containerName>
#容器重命名
docker container rename <containerName> <newName>
#进入某一正在运行容器(终端模式)
docker container exec -it <containerName> /bin/bash
#退出某容器(在容器终端中执行)
exit
#查看容器的占用情况(实时占用情况[CPU,RAM,NET])
docker container stats <containerName>
#查看某容器的详细信息(端口映射,磁盘映射,虚拟网段IP,维护者等等)
docker container inspect <containerName>
(四)容器的网络/存储隔离以及共享目录的配置
以下操作与image镜像本身无关,都是在执行run命令时配置(run配置参数只跟container实例,与image镜像无关)
- 网络隔离(下能通上,上不通下【与路由器以路由方式嵌套理解相同】)
容器间网络互通(不管是不是由同一镜像产生的容器实例),因为他们在同一个虚拟网段下(默认在172.17.0.1),且这些容器都可以ping通宿主机(物理机)也可以通过物理机连接互联网(因为访问上层网络没有问题),但对于宿主机来说,其无法直接访问(ping通)任何一个容器,因为虚拟网段是模拟出来的,他是宿主机所在的下一级网段,没办法直接访问。
【这点和路由器之间以路由模式相接相同,假如192.168.1.1为一个路由,192.168.1.2为子路由,他的网关地址为192.168.123.1,其存在2个主机:192.168.123.2与192.168.123.3,此处通过192.168.1.x的主机直接直接访问192.168.123.x不可能访问成功,因为路由访问只能访问同级和上级的网络,只能访问192.168.123.x所属的上层网络ip:192.168.1.2,由该路由器配置DMZ/端口映射到其子层网络】
查看容器所在网段配置(类似于172.17.0.X)
docker network inspect bridge
【解决方案:对容器开启端口映射】
因此为了能让宿主机能访问【必然如此,不然在容器里运行的服务暴露不出来】,docker在执行run命令的时候提供了可配置的参数
#指定单个端口
docker run -dit --name <想取的容器名> -p <宿主机端口>:<容器内服务端口> <镜像名>
#指定多个端口
docker run -dit --name <想取的容器名> -p <宿主机端口>:<容器内服务端口> -p <宿主机端口>:<容器内服务端口> <镜像名>
注意:
- 只能在首次创建容器运行时(docker run命令)候指定端口映射,已有的容器无法添加
- 指定端口映射创建出来的容器container以后就直接启动,无需再次指定端口,只需确保宿主机端口未被占用即可开启
- 若实在要对已有容器container添加/修改端口映射,只能将当前容器提交commit为一个新的镜像,然后再用该镜像run一个新的容器(此时指定端口映射)
docker container commit <containerName> <newImageName>
- 存储隔离
Docker容器Container实例之间的存储是相互隔离,互不影响的,容器Container产生的文件叫做磁盘镜像文件(DiskImage)这点和虚拟机相同,他的位置根据之前在DiskImageLocation目录:vhdx文件大小上限可以配置。默认64GB,所有容器Container实例的数据都存在这一个磁盘镜像文件中
- 共享目录配置
Docker容器可共享使用宿主机(物理机)中的某一文件目录,该文件目录需要事先配置为共享文件夹,然后在首次创建并运行容器时追加-v参数进行指定(与端口映射相同,只能在这个时机指定)
[Windows指定共享目录]
(本步骤是对windows文件夹的权限指定,即让docker拥有以下文件夹权限)
[Linux(Ubuntu)指定共享目录]
无需额外配置,只需在docker run时指定-v参数即可
【磁盘映射参数(也可指定多个)】
#-v <宿主机目录>:<容器环境需要挂载的地方>
#例
docker run -dit --name testMultiFolderMapping -v E:/DockerShareFolder:/mnt/folder1 -v E:/Share:/mnt/folder2 ercircle/ubuntu_server
- 超级权限(一般不需要)
在首次创建并运行run容器container实例时,添加以下参数:--privileged=true可以配置容器内环境具备超级管理员的权限。甚至允许在容器中再次搭建docker
--privileged=true
#例
docker run -dit --name Test --privileged=true ercircle/ubuntu_server
- 指定时区(可安装后提交为镜像,以后直接使用这个镜像)
容器时间默认和宿主机相同,但时区使用的是UTC+0即太平洋时区,要改为东八区,由于docker容器的权限有限,需要安装tzdata来调整
sudo apt-get install tzdata
- 配置某一容器自动启动
可以在首次docker run时追加参数,也可以对已有的container进行设置
#首次运行时指定该容器实例自启
docker run --restart=always
#对已有的容器设置为自启
docker update --restart=always <CONTAINER ID>
(五)修改Docker镜像并push至库
核心概念:
- 镜像的仓库没有版本控制,每一次提交都是一个新的镜像,新的镜像和之前没有关系(imageName相同,tag不同也算是不同的image)
- 镜像Image本身不可修改,所谓的修改是对其生成的容器Container实例进行操作后,提交commit后为一个新的镜像
提交Commit命令:
#对于某镜像的容器实例修改后提交为一个新的镜像(镜像名可与之前的相同(但此时必须指定tag【一般设置为版本号】))
docker container commit -m "本次提交内容" -a "作者信息" <containerName> <newImageName>:<可指定tag(代表版本)>
配置阿里云镜像管理服务:
将自己的镜像push到阿里云镜像管理服务中(自己的远端镜像仓库)
官网:阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台
(1)准备工作:配置账户密码,创建命令空间,确定好地域节点名
(2)创建命名空间,创建镜像仓库(使用本地仓库模式)
(3)执行docker命令登录到目标节点:
docker login --username=五航战瑞鹤酱 registry.cn-shanghai.aliyuncs.com
(4)列出本地镜像,确定要提交的镜像id或者名字,执行tag操作修改image名
Tag后原image不影响,依然存在,会产生一个imageId相同,imageName为新设置的镜像,新设置的镜像name需要指定为固定格式:地域节点/com/命名空间/镜像仓库名:,tag一般指定为版本号
docker tag [ImageId] registry.cn-shanghai.aliyuncs.com/zuikaku/pilipili-web-ubuntu:1.0
(5)执行提交push操作
docker push registry.cn-shanghai.aliyuncs.com/zuikaku/pilipili-web-ubuntu:1.0
push完成后,在镜像版本中可以看到这次push的记录,未指定tag,则默认为latest(最新的)
如果后续需要拉取,则到基本信息中:执行docker pull
docker pull registry.cn-shanghai.aliyuncs.com/zuikaku/init-ubuntu:<镜像版本号>
(六)在项目中使用dockerfile实现自动化部署
[1]修改docker.service
Ubuntu版的docker目录在:/etc/systemd/system/multi-user.target.wants/docker.service
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock
修改完后重新应用
systemctl daemon-reload systemctl restart docker
访问2375端口进行验证
[2]项目中配置docker
- pom.xml添加docker的maven插件依赖
<!--使用docker-maven-plugin插件-->
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<!--指定生成的镜像名-->
<imageName>nanoda/${project.artifactId}</imageName>
<!--指定标签(一般为版本)-->
<imageTags>
<imageTag>1.2</imageTag>
</imageTags>
<!-- 指定 Dockerfile 路径:项目根目录-->
<dockerDirectory>${project.basedir}</dockerDirectory>
<!--指定远程 docker api地址-->
<dockerHost>http://www.zuikakuedu.top:2375</dockerHost>
</configuration>
</plugin>
- 项目根目录添加Dockerfile文件
Dockerfile的组成成分:
#指定以哪个image作为初始镜像(此处可指定为公有仓库链接)【推荐先在宿主机把该image事先pull下来,避免docker build时因权限不足的报错】
FROM <镜像远端地址>
#指定该镜像的维护者信息
MAINTAINER <维护者姓名> <联系邮箱(可选)>
#添加哪些文件到目标镜像的目录(一般添加jar包,为tar时会自动解压,镜像环境的目录不存在时会自动创建)
ADD <以项目目录根目录下的文件或目录(相对路径)> <镜像环境的目标目录(绝对路径)>
#指定需要在目标镜像产生的容器中执行的初始化操作(可按顺序指定多条)
RUN <Linux命令1>
RUN <Linux命令2>
#指定需要暴露的端口(仅声明要暴露的端口,方便-P自动映射,手动映射依然需要在run时指定-p参数)
EXPOSE <端口1> <端口2>
#指定挂载点,自动实现路径映射,宿主机地址为随机生成(可通过docker container inspect查看,若要手动指定需要run时指定-v参数)
VOLUME ["/mnt/folder1","/mnt/folder2"]
#指定环境,如JDK,Tomcat目录,编码环境等
ENV LANG C.UTF-8
#指定容器创建完成的运行的命令,容器从关闭状态变为启动后执行的命令(一般用于启动某程序,或者执行某shell)
ENTRYPOINT ["Linux命令","参数1","参数2",...]
案例:
FROM registry.cn-shanghai.aliyuncs.com/zuikaku/ubuntu1804-init-env:1.0
MAINTAINER nanoda tanyu159@live.com
ADD target/oc-0.0.1-SNAPSHOT.jar /home/admin/ZuikakuOnlineCourse/oc.jar
RUN mkdir /home/admin/ZuikakuOnlineCourse/storage
EXPOSE 9091
ENV LANG C.UTF-8
ENTRYPOINT ["nohup","java","-jar","/home/admin/ZuikakuOnlineCourse/oc.jar",">log.txt","&"]
【3】先执行项目package打包
Maven-Package执行打包生成target,确认jar包存在
【4】再执行docker build操作(如果需要重新build,需先进行maven-clean重新打包在docker build,清除docker的一些临时文件)
【5】回到宿主机docker run该新镜像
docker run -dit --name zuikaku-oc -p 9091:9091 -v /home/admin/ZuikakuOnlineCourse/storage/:/home/admin/ZuikakuOnlineCourse/storage nanoda/oc:1.1
特别注意:
可以发现,在进行docker自动化部署,开启2375端口,在项目中指定目标地址:端口,直接执行docker build命令是没有任何身份验证的,这也就说明存在漏洞,黑客可以扫描公网ip及其该端口注入内容,因此2375端口不应在公网开启,仅在局域网内访问,应该挂入vpn或者使用堡垒机的方式进行网络连接,实现docker build
(7)docker可视化管理工具portainer
portainer提供了一种可视化管理docker的方式,本质是一个网页后台,其本身也是作为docker的image存在,使用流程如下:
【1】搜索该镜像:docker search portainer
【2】拉取该镜像:docker image pull portainer/portainer
【3】运行该镜像:需指定端口映射,容器内端口为9000,并开启超级权限和目录映射
docker run -d --name portainerUI -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock portainer/portainer
【4】放开防火墙,在外网访问该服务