概念
问题
before:
项目部署存在的问题:大型项目组件较多(例如nginx、redis、MQ、mysql等等), 运行环境也较为复杂,部署的时候经常会碰到一些问题。发布之后,扩容和缩容也会遇到问题。
after:
同操作系统下,Docker将应用的Libs(函数库)、Deps(依赖)、配置与应用一起打包。将每个应用放到一个隔离容器去运行,避免相互干扰。不同操作系统,Docker将用户程序与所需要调用的系统函数库打包。
理念
一次镜像,处处运行。从搬家到搬楼。
容器和虚拟机
传统虚拟机
带环境安装的一种解决方案。可以在一种操作系统中运行另一种操作系统,应用对此毫无感知。而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删除,对其他部分毫无影响。它能够使应用程序、操作系统和硬件三者之间逻辑不变。
存在问题:
1、资源占用多
2、冗余步骤多
3、启动慢
容器虚拟化技术
Linux容器是与系统其他部分隔离开的一系列进程,从另一个镜像运行,并由该镜像提供支持进程所需要的全部文件。容器提供的镜像包含了应用所有依赖项,因而在从开发到测试再到生产的整个过程中他都具备可移植性和一致性。
即,Linux容器不是模拟一个完全的操作系统,而是对进程进行隔离。有了容器 就可以将软件运行所需的所有资源打包到一个隔离的容器中。
对比
容器与虚拟机不同,不需要捆绑一整套操作系统,只需要软件工作所需要的资源库和设置。系统因而变得高效轻量并保证部署在任何环境中的软件都能始终如一的运行。
Docker容器是在操作系统层面实现虚拟化,直接复用本地主机的操作系统。而传统虚拟机则是在硬件层面实现虚拟化。与传统的虚拟机相比,Docker优势体现为启动速度快、占用体积小。
Docker架构
Docker是一个C/S架构的程序,由两部分组成:
服务端server:Docker守护进程,负责处理docker指令,管理镜像、容器等。
客户端client:通过命令或RestAPI向Docker服务端发送指令。可以在本地或远程向服务端发送指令。
Docker安装
官网
仓库 DockerHub:是Docker镜像的托管平台,是安装docker镜像的仓库。这样的平台称为Docker Registry。
CentOS Docker安装
Docker并非是一个通用的工具,他依赖于已存在并运行的Linux内核环境。
Docker实质上是在已经运行的Linux下制造了一个隔离的文件运行环境,因此它的执行效率几乎等同于所部属的Linux主机。
1、确认CentOS版本为7及以上
2、卸载旧版本
3、yum安装gcc相关
保证CentOS 7 能连接外网
yum -y install gcc
yum -y install gc-c++
4、安装需要的软件包
yum install -y yum-utils
5、设置stable镜像文件(不要按照官网操作,以后会访问超时)
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
6、更新yum软件包索引
yum makecache fast
7、 安装Docker CE
yum -y install docker-ce docker-ce-cli containerd.io
8、启动docker
systemctl start docker
9、测试
docker version
0、卸载
systemctl stop docker
yum remove docker-ce docker-ce-cli containerd.io
rm -rf /var/lib/docker
rm -rf /var/lib/containerd
MacOS 安装
配置镜像加速器
CentOS配置
使用阿里云镜像加速
mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://aa25jngu.mirror.aliyuncs.com"]
}
EOF
Mac配置
Setting–Docker Engine追加:
"registry-mirrors": [
"https://1tmdnhkx.mirror.aliyuncs.com"
]
Docker基本组成
类比Java,Book就相当于镜像,b1、b2、b3就相当于容器
Book b1=new Book();
Book b2=new Book();
Book b3=new Book();
在Docker中,镜像就是模板,run出实例
Redis r1=docker run镜像 # 类似鲸鱼背上的集装箱,就是一个容器实例
镜像
镜像就是一个只读的模板。镜像可以用来创建Docker容器,一个镜像可以创建很多容器。他也相当于一个root文件系统(将应用程序及所需要的依赖、函数库、环境、配置等文件打包在一起)。比如官方镜像centos 7就包含了一套centos 7最小系统的root文件系统。
容器
Docker利用容器Container独立运行一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器使用镜像创建的运行实例,每个容器都是相互隔离的、保证安全的平台。
可以把容器看作一个简易版的Linux环境(包括用户权限、进程空间、用户空间、网络空间等)和运行在其中的应用程序。
镜像中的应用程序运行后形成的进程就是容器,只是Docker会给容器做隔离,对外不可见。
仓库
仓库是集中存放镜像的,推荐阿里云的
关系:
容器之间相互隔离。
容器对镜像是只读的,即容器不能往镜像写,只能从镜像读。想要写(例如mysql要写数据),只能从镜像拷贝一份到容器中去写,这样就不会影响镜像或别的容器了。
Docker架构
Docker工作原理
Docker是一个C/S结构的系统,Docker守护线程运行在主机上,然后通过Socket连接从客户端访问,守护进程从客户端接受命令并管理运行在主机上的容器。
Docker的后端是一个松耦合的架构,众多模块各司其职。
运行基本流程:
卸载
使用yum命令网上搜一搜
Docker常用操作
帮助启动类命令
启动docker: systemctl start docker
停止docker: systemctl stop docker
重启docker: systemctl restart docker
查看docker状态: systemctl status docker
开机启动: systemctl enable docker
查看docker概要信息: docker info
查看docker总体帮助文档: docker --help
查看docker命令帮助文档: docker 具体命令 --help
镜像命令
docker images :列出本地主机上的镜像
各列说明:
REPOSITORY:表示镜像的仓库源
TAG:镜像的标签版本号
IMAGE ID:镜像ID
CREATED:镜像创建时间
SIZE:镜像大小
注意: 同一仓库源可以有多个 TAG版本,代表这个仓库源的不同个版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。
如果你不指定一个镜像的版本标签,例如你只使用 ubuntu,docker 将默认使用 ubuntu:latest 镜像
OPTIONS说明:
-a :列出本地所有的镜像(含历史映像层)
-q :只显示镜像ID。
docker search [OPTIONS] 镜像名字:搜索镜像
各列说明:
NAME:镜像名称
DESCRIPTION:镜像说明
STARS:点赞数
OFFICIAL:是否是官方的
AUTOMATION:是否是自动构建的
如果搜出来有多个的话,一般使用没有前缀的,前缀相当于包名。
OPTIONS说明:
–limit : 只列出N个镜像,默认25个
docker search --limit 5 redis
docker pull 某个XXX镜像名字[:TAG]:下载镜像
docker system df:查看镜像/容器/数据卷所占的空间
docker rmi 某个XXX镜像名字ID:删除镜像
OPTIONS说明:
-f :强制删除
删除单个
docker rmi -f 镜像ID
删除多个
docker rmi -f 镜像名1:TAG 镜像名2:TAG
删除全部
docker rmi -f $(docker images -qa)
虚悬镜像:
定义:仓库名、标签都是<none>
的镜像,俗称虚悬镜像dangling image
容器命令
docker run [OPTIONS] IMAGE_NAME/IMAGE_ID [COMMAND] [ARG...]
:新建+启动容器
生成容器实例id就表示成功
OPTIONS说明:
–name=“容器新名字”
-d: 后台运行容器并返回容器ID,也即启动守护式容器(后台运行);
-i:以交互模式运行容器,通常与 -t 同时使用;
-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;也即启动交互式容器(前台有伪终端,等待交互);
一般docker run -it ubuntu
-P: 随机端口映射,大写P
-p: 指定端口映射,小写p。例如:-p 8080:80
-e:指定运行环境
参数 | 说明 |
---|---|
-p hostPort:containerPort | 端口映射 -p 8080:80 |
-p ip:hostPort:containerPort | 配置监听地址 -p 10.0.0.100:8080:80 |
-p ip::containerPort | 随机分配端口 -p 10.0.0.1::80 |
-p hostPort:containerPort:udp | 指定协议 -p 8080:80:tcp |
-p81:80 -p 443:443 | 指定多个 |
示例:
在Docker中启动Ubuntu,需要Shell窗口交互
docker run - it ubuntu /bin/bash
# 以交互模式启动一个容器,在容器内执行/bin/bash命令。
# /bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。
# 退出终端 直接输入exit
docker ps [OPTIONS]:列出当前所有正在运行的容器
OPTIONS说明(常用):
-a :列出当前所有正在运行的容器+历史上运行过的
-l :显示最近创建的容器。
-n x:显示最近x个创建的容器。
-q :静默模式,只显示容器编号。
exit 退出容器
run进去容器,exit退出,容器停止
ctrl+p+q 退出容器
run进去容器,ctrl+p+q退出,容器不会停止
docker start 容器ID/容器名:启动已停止运行的容器
docker restart 容器ID/容器名:重启容器
docker stop 容器ID/容器名:停止容器
docker kill 容器ID/容器名:强行停止容器
docker rm 容器ID:删除已停止的容器
不能删正在使用的容器
强制删除正在使用的容器docker rm -f 容器ID/容器名
docker run -d 容器名:启动守护式容器
运行后都需要,docker ps
查看
Docker容器后台运行,就必须有一个前台进程。容器运行的命令如果不是那些一直挂起的命令(比如top,tail),就是会自动退出的。
总之,有的后台启动就会自动关闭,这时需要前台启动。
像Redis、MySQL之类的就适合后台启动
docker logs 容器ID:查看容器日志
docker top 容器ID:查看容器内进程
docker inspect 容器ID:查看容器内部细节
docker exec -it 容器ID [bashShell]:重新进入容器
例如docker exec -it 23456asdf24 /bin/bash
[OPTIONS说明] 见docker exec --help
docker attach 容器ID:重新进入容器
两者区别
attach 直接进入容器启动命令的终端,不会启动新的进程,因此用exit退出,会导致容器的停止。
exec 是在容器中打开新的终端,并且可以启动新的进程,因此用exit退出,不会导致容器的停止。
因此,一般使用 exec,这样用exit退出,进程不会停止。
一般使用 -d 后台启动程序,在用exec进入对应容器实例
docker cp 容器ID:容器内路径 目的主机路径 从容器拷贝文件到主机
docker export 容器ID > 文件名.tar :导出容器
导出的路径是默认为当前目录。
cat 文件名.tar | docker import -镜像用户/镜像名:镜像版本号 导入容器为镜像
再使用docker run 镜像ID
来重建容器。
常用
attach Attach to a running container # 当前 shell 下 attach 连接指定运行镜像
build Build an image from a Dockerfile # 通过 Dockerfile 定制镜像
commit Create a new image from a container changes # 提交当前容器为新的镜像
cp Copy files/folders from the containers filesystem to the host path #从容器中拷贝指定文件或者目录到宿主机中
create Create a new container # 创建一个新的容器,同 run,但不启动容器
diff Inspect changes on a container’s filesystem # 查看 docker 容器变化
events Get real time events from the server # 从 docker 服务获取容器实时事件
exec Run a command in an existing container # 在已存在的容器上运行命令
export Stream the contents of a container as a tar archive # 导出容器的内容流作为一个 tar 归档文件[对应 import ]
history Show the history of an image # 展示一个镜像形成历史
images List images # 列出系统当前镜像
import Create a new filesystem image from the contents of a tarball # 从tar包中的内容创建一个新的文件系统映像[对应export]
info Display system-wide information # 显示系统相关信息
inspect Return low-level information on a container # 查看容器详细信息
kill Kill a running container # kill 指定 docker 容器
load Load an image from a tar archive # 从一个 tar 包中加载一个镜像[对应 save]
login Register or Login to the docker registry server # 注册或者登陆一个 docker 源服务器
logout Log out from a Docker registry server # 从当前 Docker registry 退出
logs Fetch the logs of a container # 输出当前容器日志信息
port Lookup the public-facing port which is NAT-ed to PRIVATE_PORT # 查看映射端口对应的容器内部源端口
pause Pause all processes within a container # 暂停容器
ps List containers # 列出容器列表
pull Pull an image or a repository from the docker registry server # 从docker镜像源服务器拉取指定镜像或者库镜像
push Push an image or a repository to the docker registry server # 推送指定镜像或者库镜像至docker源服务器
restart Restart a running container # 重启运行的容器
rm Remove one or more containers # 移除一个或者多个容器
rmi Remove one or more images # 移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或 -f 强制删除]
run Run a command in a new container # 创建一个新的容器并运行一个命令
save Save an image to a tar archive # 保存一个镜像为一个 tar 包[对应 load]
search Search for an image on the Docker Hub # 在 docker hub 中搜索镜像
start Start a stopped containers # 启动容器
stop Stop a running containers # 停止容器
tag Tag an image into a repository # 给源中镜像打标签
top Lookup the running processes of a container # 查看容器中运行的进程信息
unpause Unpause a paused container # 取消暂停容器
version Show the docker version information # 查看 docker 版本号
wait Block until a container stops, then print its exit code # 截取容器停止时的退出状态值
Docker镜像-细致
review:
镜像是轻量级、可执行的独立软件包,它包含运行某个软件需要的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。
只有通过这个镜像文件才能生成Docker容器实例。
概念 - 定义
分层的镜像
以我们的pull为例,在下载的过程中我们可以看到docker的镜像好像是在一层一层的在下载。
UnionFS 联合文件系统
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
Docker镜像加载原理
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。
bootfs(boot file system)主要包含bootloader (引导虚文件系统) 和kernel (Linux内核) , bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就行了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
采用分层结构原因
镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。
比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
重点
Docker镜像层都是只读的,容器层是可写的。当容器启动时,一个新的可写层被加载到镜像的顶部。 这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。
Docker镜像commit操作案例
先拉下来一个默认原始的ubuntu
执行docker run -it ubuntu /bin/bash
再尝试执行vim a.txt
会发现 command not found,说明没有这个命令。这时就需要在这个ubuntu安装vim命令
# 先更新我们的包管理工具,ubuntu使用的apt-get 相当于CentOS的yum
apt-get update
# 然后安装我们需要的vim
apt-get -y install vim
安装完成后,commit我们自己的新镜像。docker commit -m="描述信息" -a="作者" 容器ID 镜像用户/镜像名:镜像版本号
Docker镜像发布到阿里云
推送镜像到阿里云,操作参考控制台的操作指南
Docker私人仓库
Docker Registry是官方提供的工具,用来构建私有镜像仓库。
参考视频
容器数据卷
Docker挂载主机目录访问,如果初见cannot open directory:Permission denied
解决办法:再挂载目录后多加一个--privileged=true
参数
示例:docker run -d -p 5000:5000 -v /zzyyuser/myregistry/:/tmp/registry --privileged=true registry
其中:
-v
表示要添加自定义容器卷
冒号前/zzyyuser/myregistry/
是宿主机路径
冒号后/tmp/registry
是容器内路径
--privileged=true
是放开权限,是容器启动后 容器内路径和宿主机路径的信息共享、互通互联
用途
容器目录和宿主机目录的映射,完成数据的持久化到本地主机目录。
1:数据卷可在容器之间共享或重用数据
2:卷中的更改可以直接实时生效,爽
3:数据卷中的更改不会包含在镜像的更新中
4:数据卷的生命周期一直持续到没有容器使用它为止
定义
卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性:
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷
使用
示例:运行一个带有容器卷 存储功能的容器实例docker run -it -- privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
v可以有多个
查看数据卷是否挂载成功:docker inspect 容器ID
,找到"Mounts"
读写规则
只能限制容器
上述的操作中使用的默认规则:rw
docker run -it -- privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名
如果将rw改为ro:容器实例内部被限制,只能读取不能写
docker run -it -- privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
容器卷的继承
启动命令docker run -it -- privileged=true --volumes-from 父类 --name 容器名 ubuntu
,增加的命令是--volumes-from 父类
如果 父类容器 被停止了,那也不会影响子类的继承情况。子类依旧能访问这个路径。
父类 如果恢复的话,依旧能看见所有的
Docker安装软件
总体步骤
搜索镜像、拉取镜像、查看镜像、启动镜像(服务端口映射)、停止镜像、移除镜像
tomcat
docker hub上面查找tomcat镜像:docker search tomcat
从docker hub上拉取tomcat镜像到本地:docker pull tomcat
docker images查看是否有拉取到的tomcat:docker images tomcat
使用tomcat镜像创建容器实例:docker run -it -p 8080:8080 tomcat
坑:
1、在linux中用localhost:8080
访问tomcat页面,会遇到404错误。
原因:可能没有映射端口或者没有关闭防火墙
解决: 看看tomcat下的目录是不是有webapps
和web app s.dist
先删除rm -r webapps
再重命名mv webapps.dist webapps
免修改版tomcat
拉docker pull billygoo/tomcat8-jdk8
启动docker run -d -p 8080:8080 --name mytomcat8 billygoo/tomcat8-jdk8
MySQL
基础版(一般不用)
docker hub上面查找mysql镜像docker search mysql
从docker hub上(阿里云加速器)拉取mysql镜像到本地标签为5.7docker pull mysql:5.7
运行docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
这里设置了root的密码为123456,登录的时候使用这个就行
坑:
1、插入中文数据报错
原因:docker默认字符集,在docker的mysql中执行SHOW VARIABLES LIKE 'character%'
,发现字符集是Latin1不是UTF-8
2、容器删除数据丢失
原因:没有容器数据卷
实操版MySQL
zzyyuse是用户,需要按需修改
启动MySQLdocker run -d -p 3306:3306 --privileged=true -v /zzyyuse/mysql/log:/var/log/mysql -v /zzyyuse/mysql/data:/var/lib/mysql -v /zzyyuse/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7
新建 my.cnf 解决中文乱码问题:在宿主机中:
执行cd /zzyyuse/mysql/conf/
执行vim my.cnf
执行cat my.cnf
输入:
[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8
在docker的mysql中执行SHOW VARIABLES LIKE 'character%'
查看字符集
修改完之后,新建的DB才有效 之前的DB修改无效
MySQL容器被删除后恢复
如果执行了docker rm -f mysql
删除了MySQL容器
重新用相同命令docker run -d -p 3306:3306 --privileged=true -v /zzyyuse/mysql/log:/var/log/mysql -v /zzyyuse/mysql/data:/var/lib/mysql -v /zzyyuse/mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7
启动MySQL之后,原来的数据是存在的。这是因为容器卷存在。
Redis
拉取Redis:docker pull redis:6.0.8
启动Redis:docker run -d -p 6379:6379 redis:6.0.8
进入Redis:docker exec -it 容器ID /bin/bash
进入Redis后启动客户端:redis-cli
执行命令…
存在问题:
1、数据持久化
2、配置文件
实操版Redis
1、在宿主机下新建目录mkdir -p /app/redis
2、讲一个redis.conf文件模板拷贝进/app/redis
目录下
3、修改上一步的配置文件
1、允许Redis外地连接,注释掉bind 127.0.0.1,这个可能有多个
# bind 127.0.0.1 ::1
2、允许后台启动,注释掉daemonize no,因为该配置和docker run中-d参数冲突,会导致容器一直启动失败
# daemonize yes 把yes改为no
daemonize no
3、保护模式改为no
protected-mode no
4、运行镜像创建容器:docker run -p 6379:6379 --name myr3 --privileged=true -v /app/redis/redis.conf:/etc/redis/redis.conf -v /app/redis/data:/data -d redis:6.0.8 redis-server /etc/redis/redis.conf
最后是让redis去读配置文件
5、测试redis-cli连接上来