Docker——容器虚拟化技术
第一章 Docker介绍
诞生背景
一款产品从开发到上线,从操作系统,到运行环境,再到应用配置。
作为开发+运维之间的协作我们需要关心很多东西,这也是很多互联网公司都不得不面对的问题,
特别是各种版本的迭代之后,不同版本环境的兼容,对运维人员都是考验 .
Docker之所以发展如此迅速,也是因为它对此给出了一个标准化的解决方案。
环境配置如此麻烦,换一台机器,就要重来一次,费力费时。
很多人想到,能不能从根本上解决问题,软件可以带环境安装?
也就是说,安装的时候,把原始环境一模一样地复制过来。
开发人员利用 Docker 可以消除协作编码时“在我的机器上可正常工作”的问题。
开发需要清楚的告诉运维部署团队,用的全部配置文件+所有软件环境。
不过,即便如此,仍然常常发生部署失败的状况。
Docker镜像的设计,使得Docker得以打破过去”程序即应用” 的观念。
透过镜像(images)将作业系统核心除外,运作应用程式所需要的系统环境,
由下而上打包,达到应用程式跨平台间的无缝接轨运作。
Docker 介绍
Docker的主要目标是“Build,Ship and Run Any App,Anywhere”,
也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,
使用户的APP(可以是一个WEB应用或数据库应用等等)及其运行环境能够做到“一次封装,到处运行”。
Linux 容器技术的出现就解决了这样一个问题,而 Docker 就是在它的基础上发展过来的。
将应用运行在 Docker 容器上面,而 Docker 容器在任何操作系统上都是一致的,
这就实现了跨平台、跨服务器。只需要一次配置好环境,换到别的机子上就可以一键部署好, 大大简化了操作
总结:
Docker是解决运行环境和配置问题的软件容器 , 方便做持续集中并有助于整体发布的容器虚拟化技术
虚拟机技术与容器虚拟化技术
虚拟机技术
虚拟机(virtual machine)就是带环境安装的一种解决方案。
它可以在一种操作系统里面运行另一种操作系统,比如在Windows 系统里面运行Linux 系统。
应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样
缺点 :1 资源占用多 2 冗余步骤多 3 启动慢
容器虚拟化技术
Linux 容器(Linux Containers,缩写为 LXC)。
Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离。
有了容器,就可以将软件运行所需的所有资源打包到一个隔离的容器中。
容器与虚拟机不同,不需要捆绑一整套操作系统,只需要软件工作所需的库资源和设置。
系统因此而变得高效轻量并保证部署在任何环境中的软件都能始终如一地运行。
二者区别
- 传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;
- 而容器内的应用进程直接运行于宿主机( 即:所在主机,下面统称宿主机 ) 的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
- 每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。
官方网址
官方网址 : https://www.docker.com
Docker社区官方:https://hub.docker.com/
第二章 Docker安装
Docker支持以下的CentOS版本:CentOS 7 (64-bit) ,CentOS 6.5 (64-bit) 或更高的版本
前提条件
目前,CentOS 仅发行版本中的内核支持 Docker。
Docker 运行在 CentOS 7 上,要求系统为64位、系统内核版本为 3.10 以上。
Docker 运行在 CentOS-6.5 或更高的版本的 CentOS 上,要求系统为64位、系统内核版本为 2.6.32-431 或者更高版本。
# 查看内核版本
uname -r
安装Docker
Docker安装教程(CentOS 7)本人阿里云服务器安装成功
Docker安装教程(CentOS 7)本人腾讯云服务器安装成功
Docker安装教程(CentOS 6)
Docker安装教程(Ubuntu) 本人腾讯云服务器安装成功
Docker管理命令
# 重新载入后台启动进程
systemctl daemon-reload
# 启动docker容器 ,每次关闭虚拟机/运服务器时需要启动( 重要!!! )
sudo service docker start
# 查看Docker容器状态
sudo service docker status (should see active (running))
# 运行hello-world镜像/测试Docker是否可以使用
sudo docker run hello-world
Docker底层原理
Docker结构图
工作原理
Docker是一个Client-Server结构的系统,Docker守护进程运行在主机上,
然后通过Socket连接从客户端访问,守护进程从客户端接受命令并管理运行在主机上的容器。
容器,是一个运行时环境,就是我们前面说到的集装箱。
Docker为什么比VM快
(1) docker有着比虚拟机更少的抽象层。
由亍docker不需要Hypervisor实现硬件资源虚拟化,
运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。
因此在CPU、内存利用率上docker将会在效率上有明显优势。
(2) docker利用的是宿主机的内核,而不需要Guest OS。
因此,当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。
因而避免引寻、加载操作系统内核返个比较费时费资源的过程,
当新建一个虚拟机时,虚拟机软件需要加载Guest OS,返个新建过程是分钟级别的。
而docker由于直接利用宿主机的操作系统,则省略了返个过程,因此新建一个docker容器只需要几秒钟。
通过下图着重了解二者的比较( 图很重要!!!)
第三章 Docker常用命令
帮助命令
# 查看docker版本信息
docker version
# 查看docker所有安装信息
docker info
# 查看docker帮助 ( 最为重要,学会利用帮助文档来学习 ,这是成为高手的必经之路!!! )
docker --help
镜像命令
# 1.列出本地镜像(图1)
docker images
# option说明
-a :列出所有镜像
-q:只列出镜像id
-digests :显示镜像的摘要信息
--no-trunc :显示相信信息
# 2.搜索某个镜像名字 (会在docker社区搜索相关的镜像, 而我们配置的阿里源只是帮我们同步了docker社区的镜像,图2)
docker search
# option说明
- s显示收藏数不小于指定值的镜像
--no-trunc :显示相信信息
- automated :只列出automated类型的镜像
# 3. 下载镜像(图3)
docker pull 镜像的名字:[TAG](不写默认为 lasted)
# 4. 删除镜像
docker rmi -f 镜像id/image_name:tag
## 4.1 删除所有镜像
docker rmi -f $(docker images -qa )
## 4.2 如果容器名称=镜像名称, 则可根据名称删除镜像(脚本中会用到, 需先把容器stop和rm后执行)
docker rmi $( docker images image_name | awk 'NR==2{print $3}')
# 5. 复制镜像和加载镜像
## 5.1 使用以下命令将需要复制的镜像保存为tar文件:
docker save -o image.tar <image_name>:<tag>
## 5.2 将tar文件复制到目标机器上,可以使用scp或其他文件传输工具。
## 5.3 在目标机器上,使用以下命令将tar文件中的镜像加载到本地(-i选项用于指定tar文件的输入路径和文件名):
docker load -i image.tar
图1
各个选项说明:
- REPOSITORY:表示镜像的仓库源
- TAG:镜像的标签
- IMAGE ID:镜像ID
- CREATED:镜像创建时间
- SIZE:镜像大小
- 同一仓库源可以有多个 TAG,代表这个仓库源的不同个版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。如果你不指定一个镜像的版本标签,例如你只使用 ubuntu,docker 将默认使用 ubuntu:latest 镜像
图2
图3
容器命令
基本命令
# 1. 新建并启动容器
docker run [OPTIONS] IMAGE [COMMOND] [ARGS...]
# OPTIONS 说明
--name="容器新名字": 为容器指定一个名称;
-d: 后台运行容器,并返回容器ID,也即启动守护式容器;
-i:以交互模式运行容器,通常与 -t 同时使用;
-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;
-P: 随机端口映射;
-p: 指定端口映射,有以下四种格式
ip:hostPort:containerPort
ip::containerPort
hostPort:containerPort
containerPort
# eg: 使用镜像centos:latest以交互模式启动一个容器,在容器内执行/bin/bash命令。
docker run -it centos /bin/bash
# 2. 查询当前正在运行的容器(类比虚拟中的查看进程)
docker ps [OPTIONS]
# OPTIONS说明(常用):
-a :列出当前所有正在运行的容器+历史上运行过的
-l :显示最近创建的容器。
-n:显示最近n个创建的容器。
-q :静默模式,只显示容器编号。
--no-trunc :不截断输出。
# 3. 退出容器
exit 容器停止后退出
ctrl+p+q 容器不停止退出
# 4 .启动容器
docker start 容器ID/容器名
# 5. 重启容器
docker restart
# 6. 停止容器
docker stop 容器ID/容器名
# 7. 强制停止容器
docker kill 容器ID/容器名
# 8. 删除已经停止的容器(如果没有停止,删除后悔停止)
docker rm 容器ID
删除多个容器(特别是第二种 ,先查询所有运行的进程, 然后通过管道传到后面的删除操作中)
docker rm -f $(docker ps -a -q)
docker ps -a -q | xargs docker rm
重要命令
# 1. 启动守护式容器(后台运行)
docker -d 容器名
# 使用镜像centos:latest以后台模式启动一个容器
docker run -d centos
问题:然后docker ps -a 进行查看, 会发现容器已经退出
很重要的要说明的一点: Docker容器后台运行,就必须有一个前台进程.
容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail),就是会自动退出的。
这个是docker的机制问题,比如你的web容器,我们以nginx为例,正常情况下,我们配置启动服务只需要启动响应的service即可。例如service nginx start
但是,这样做,nginx为后台进程模式运行,就导致docker前台没有运行的应用,
这样的容器后台启动后,会立即自杀因为他觉得他没事可做了.
所以,最佳的解决方案是,将你要运行的程序以前台进程的形式运行
# 2. 查看容器日志
docker logs -f -t --tail 容器ID
eg :(图1)
docker run -d centos /bin/sh -c "while true;do echo hello testLogs;sleep 2;done"
docker logs -tf --tail 10 02c81778b0e0
-t 是加入时间戳
-f 跟随最新的日志打印
--tail 数字 显示最后多少条
# 3. 查看容器内运行的进程(图2)
docker top 容器ID
# 4. 查看容器内部细节(图3)
docker inspect 容器ID
# 5.进入正在运行的容器并进行交互(图4)
docker exec -it 容器ID bashShell
# 6. 重新进入容器(图5)
docker attach 容器ID bashShell(不写的话默认 /bin/bash下)
# 比较5与6的区别
attach 直接进入容器启动命令终端, 不会启动新的线程
exec 是在容器中打开新的终端, 并且可以启动新的线程
图1
图2
图3
图4
图5
Docker常用命令图解
第四章 Docker镜像
镜像 / UnionFS(联合文件系统)
Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,
它支持对文件系统的修改作为一次提交来一层层的叠加,
同时可以将不同目录挂载到同一个虚拟文件系统下。Union 文件系统是 Docker 镜像的基础。
镜像可以通过分层来进行继承. 基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性
一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,
联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
总结:
镜像就像洋葱圈 ,就像莲花卷 ,一层套一层 ,对外只显示一个文件系统.
而且, 这种分层镜像还可以复用
特点
Dcoker镜像都是只读的 , 当启动容器时, 一个新的可写层被加载到镜像的顶部
这一层被称为”容器层”, “容器层”执行的都称为”镜像层”
Docker镜像加载原理:
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件构成文件系统UnionFS。
bootfs(boot file system) 主要包含bootloader和kernel,
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等等。
平时我们安装进虚拟机的CentOS都是好几个G,为什么docker这里才220M
对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,
因为底层直接用Host的kernel,自己只需要提供 rootfs 就行了。
由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
Docker镜像Commit操作
# 提交容器副本实质成为一个新的镜像
docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
eg: 同时docker运行tomcat案例
# 1. 创建交互式界面 ( 相当于前台启动)
docker run -it -p 8888:8080 tomcat # 端口映射将8888作为docker的入口,映射到tomcat镜像的8080(图1,图2)
docker run -it -P tomcat #自动端口映射(通过 docker ps查看端口, 图3)
#后台启动(不会占用当前页面)
docker run -d -p 8888:8080 tomcat
# 2. 进入tomcat (如果前置启动,另开一个窗口 ,后置启动则直接进入)
# 查看运行容器ID
docker ps
# 进入根目录
docker exec -it 容器ID /bin/bash
/usr/local/tomcat# rm -rf webapps/docs/
# 删除后访问tomcat ,可以看到访问主页下的文档出现404(图4)
# 3. 提交容器副本实使之为一个新的镜像
# 查看运行容器ID
docker ps
# 提交容器
docker commit -m="del tomcat docs" -a="timepaus" 容器ID tomcat:v1.2
# 查看镜像(图5)
docker images
# 4.同时启动新镜像并和原来的对比
可以看到我们自己提交的新镜像也没有文档()
但是我们重新下载的tomcat是有的
图1
图2
图3
图4
图5
第五章 Docker容器数据卷
简介
类似Redis中的rdb文件和aof文件
用于容器的持久化和荣期间的继承与共享数据
容器内添加数据卷
1.直接命令添加
# 通过-v命令直接添加 (需要在根目录下创建 containerData )
# 创建后修改容器内containerData 会同步到hostData ,反之亦是如此
docker run -it -v /hostData:/containerData 镜像名/ID
# 创建只读权限的文件 , 容器内只能读取这个文件, 但是不能修改. ro: readonly
docker run -it -v /宿主机绝路路径目录:/容器内目录:ro 镜像名
2.Docker添加
DockerFile的简单理解
# 1. 宿主机根目录下创建mydocker文件夹并进入
# 2. 在mydocker文件想创建DockerFile文件并编辑,内容如下(图1)
# volume test
FROM centos
VOLUME ["/dataVolumeContainer1","/dataVolumeContainer2"]
CMD echo "finished,--------success1"
CMD /bin/bash
说明:
出于可移植和分享的考虑,用-v 主机目录:容器目录这种方法不能够直接在Dockerfile中实现。
由于宿主机目录是依赖于特定宿主机的,并不能够保证在所有的宿主机上都存在这样的特定目录。
3. 使用docker build命令创建一个镜像, 并挂载指定宿主机指定文件
docker build -f /mydocker/DockerFile -t 定义的新镜像名称
4. 查看镜像
docker images
5.运行新镜像
docker run -it 定义的新镜像ID /bin/bash
6.通过镜像运行后生成的容器ID查看 (图2), 对应的主机映射的数据卷地址
docker ps
docker inspect 容器ID
7.测试添加卷和主机是否互通有无
在容器中创建文件, 看看主机中是否创建对应的文件
注意:
Docker挂载主机目录(第3步)Docker访问出现cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个--privileged=true参数即可
图1
图2, 查看运行的容器id相关信息 docker inspect 容器ID
对比与总结
数据卷容器
命名的容器挂载数据卷,其它容器通过挂载这个(父容器)实现数据共享,
挂载数据卷的容器,称之为数据卷容器
实现步骤
# 1. 以上一步所建镜像为模板 ,首先启动一个父容器dc01 ,在创建容器的数据卷文夹中创建一个文件(图1)
docker run -it --name dc01 zzyy/centos
touch dc01_add.txt
# 2. 创建子容器dc02,dc03继承自dc01 , 在创建容器的数据卷文夹中创建一个文件(图2)
docker run -it --name dc02 --volumes-from dc01 zzyy/centos
touch dc02_add.txt
docker run -it --name dc03 --volumes-from dc01 zzyy/centos
touch dc01=3_add.txt
# 3. 回到dc01可以看到所有数据都被共享了(图3)
# 4. 删除dc01, dc02修改后dc03是否可访问,可以 (图4)
# 5. 删除dc02dc03是否可以访问, 可以(图5)
# 6. 新建dc04继承dc03是否可以访问, 可以(图6)
结论
容器之间配置信息的传递, 数据卷的生命周期一直持续到没有容器使用它为止
图1
图2
图3
图4
图5
图6
第六章 DockerFile解析
介绍
Dockerfile是用来构建Docker镜像文件 ,是有一系列命令和参数构成的脚本
构建步骤
1.编写Dockerfile文件
2.docker build
3.docker run
格式
以centos的文件为例
FROM scratch
ADD centos-8-container.tar.xz /
LABEL org.label-schema.schema-version="1.0" \
org.label-schema.name="CentOS Base Image" \
org.label-schema.vendor="CentOS" \
org.label-schema.license="GPLv2" \
org.label-schema.build-date="20190927"
CMD ["/bin/bash"]
语法
- 每条保留字指令都必须为答谢字母且后面至少跟一个参数
- 指令从上到下, 顺序执行
- #表示注释
- 每条指令都会创建一个一个新的镜像层, 并提交
Docker执行DockerFile的大致流程
- docker从基础镜像运行一个容器
- 执行一条指令并对容器做出修改
- 执行类似docker commit 的操作提交一个新的镜像层
- docker 再基于刚提交的镜像运行一个新容器
- 执行dockerfile 中的下一条执行, 直至所有指令都完成
从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段,
- Dockerfile是软件的原材料
- Docker镜像是软件的交付品
- Docker容器则可以认为是软件的运行态。
Dockerfile面向开发,Docker镜像成为交付标准,
Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。
1 Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
2 Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时,会真正开始提供服务;
3 Docker容器,容器是直接提供服务的
DockerFile保留字指令
查看tomcat的DockerFile文件 ,更好理解保留字
保留字整合案例
自定义镜像
我们安装的centos精简版是没有vim和ifconfig命令的支持的
我们可以通过编写Dockerfile令其支持这些功能
# 1.搜索centos镜像并下载
docker search centos
docker pull centos
# 2.编写创建一个文件( /mydoker/dockerfile_centos ),编写Dockerfile ,内容如下
--------------------------------------------------------------------
FROM centos
MAINTAINER timepause<qq_43371556@csdn.net>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "install vim and ifconfig commond plug-in components success"
CMD /bin/bash
-----------------------------------------------------------------------
# 3. 编译运行centos( 注意最后的空格和点号,图1 )
docker build -f /mydoker/dockerfile_centos -t mycentos:1.3 .
# 4. 测试功能( 图2 )
# 查看是否新增镜像
docker ps
# 运行新镜像
docker run -it mycentos:1.3
# 在容器中使用vim 与if config命令
图1
图2
自定义tomcat9
# 1. 创建存放生成镜像文件的目录
mkdir -p /myuse/mydocker/tomcat9
# 2.创建相关文件(c.txt用于测试)
touch c.txt
# 3.上传tomcat和jdk(一定要注意版本, 根据版本修改Dockerfile文件, 图1)
#. 4.创建并编辑Dockerfile(需要提前下载centos)
vim Dockerfile
---------------------Dockerfile-------------------------------
FROM centos
MAINTAINER chy<chy@qq.com>
#把宿主机当前上下文的c.txt拷贝到容器/usr/local/路径下
COPY c.txt /usr/local/cincontainer.txt
#把java与tomcat添加到容器中
ADD jdk-8u11-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.27.tar.gz /usr/local/
#安装vim编辑器
RUN yum -y install vim
#设置工作访问时候的WORKDIR路径,登录落脚点
ENV MYPATH /usr/local
WORKDIR $MYPATH
#配置java与tomcat环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_11
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.27
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.27
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#容器运行时监听的端口
EXPOSE 8080
#启动时运行tomcat
# ENTRYPOINT ["/usr/local/apache-tomcat-9.0.8/bin/startup.sh" ]
# CMD ["/usr/local/apache-tomcat-9.0.8/bin/catalina.sh","run"]
CMD /usr/local/apache-tomcat-9.0.27/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.27/bin/logs/catalina.out
---------------------Dockerfile-------------------------------
# 5.构建镜像(在存放这些文件的目录下,图2)
# 如果Dockerfile文件名称就是Dockerfile,可以省略参数 -f /Dockerfile所在位置的书写
docker build -t mytomcat9 .
# 6.查看镜像并运行镜像( 图3)
docker images
# 运行镜像 (后台启动, 成功后如图4)
docker run -d -p 8080:8080 --name myt9 -v /myuse/mydocker/tomcat9/test:/usr/local/apache-tomcat-9.0.27/webapps/test -v /myuse/mydocker/tomcat9/tomcat9logs/:/usr/local/apache-tomcat-9.0.27/logs --privileged=true mytomcat9
# 注意这里配置了容器卷的映射,宿主机的test文件夹映射到tomcat的webapps目录下的test文件,且二者可以互通有无.
docker exec -it 容器ID /bin/bash #进入容器根目录 ,可以访问相关页面
# 7. 访问成功后, 添加jsp文件与web.xml文件( a.jsp用于访问测试 ,web.xml用于令jsp页面可以编译)
vim a.jsp
mkidr WEB-INF
vim /WEB-INF/web.xml
------------------------------------------a.jsp---------------------------
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
-----------welcome------------
<="i am in docker tomcat self "%>
<br>
<br>
<% System.out.println("=============docker tomcat self");%>
</body>
</html>
------------------------------------------a.jsp---------------------------
------------------------------------------web.xml-----------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
metadata-complete="true">
</web-app>
------------------------------------------web.xml-----------------------------------
# 8. 重启服务, 访问a.jsp(图5)
# 查看当前容器id
docker ps (查看当前容器ID)
docker ps -a (查看所有运行过的容器ID)
# 重启服务
docker restart 容器ID
# 访问a.jsp页面
图1
图2
图3
图4
图5
第七章 通过Docker安装软件
MySQL
# 1. 以安装mysql5.6为例(不知道什么原因5.7下不来)
docker pull mysql:5.6
# 2. 运行镜像,启动容器(端口3306,root用户密码:root,运行镜像:mysql5.6)
docker run -p 3306:3306 --name mysql -v /datebase/mysql/conf:/etc/mysql/conf.d -v /datebase/mysql/logs:/logs -v /datebase/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.6
# 3. 进入msql内部测试登陆
docker ps
## 进入mysql的当前目录下
docker exec -it MySQL运行成功后的容器ID/name /bin/bash
## 输入账号密码
mysql -u 账号 -p(然后根据提示输入密码)
# 4.连接数据库的图形化界面
## Mysql 解决连接客户端时出现1251 client does not support ...问题
ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'mysql密码';
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'mysql密码';
# 5. 备份数据库数据,之后我们可以通过直接读取这个sql文件恢复数据
docker exec myql服务容器ID sh -c ' exec mysqldump --all-databases -uroot -p"root" ' > /datebase/all-databases.sql
Redis
# 1.下载最新版redis镜像
docker pull redis
# 2.运行镜像(redis端口2333, -d后的redis不加参数默认为redis:latest)
# 注意本地数据卷与容器内数据卷目录的对应
docker run -p 2333:6379 -v /myuse/myredis/data:/data -v /myuse/myredis/conf/redis.conf:/usr/local/etc/redis/redis.conf -d redis redis-server /usr/local/etc/redis/redis.conf --appendonly yes
# 以带密码的方式启动, 密码设置为root
docker run -p 2333:6379 -v /myuse/myredis/data:/data -v /myuse/myredis/conf/redis.conf:/usr/local/etc/redis/redis.conf -d redis redis-server /usr/local/etc/redis/redis.conf --appendonly yes --requirepass "root"
# 或者不适用上面的容器卷, 使用docker 默认配置, 并设置自动重启
docker run --name redis -p 6379:6379 -d --restart=always redis:latest redis-server --appendonly yes --requirepass "root"
# 3.上传redis.conf到本地数据卷所在目录
本地数据卷坐在目录 : /myuse/myredis/conf
文件地址(太大了 ,这里放不下) : https://download.csdn.net/download/qq_43371556/11889084
# 4. 运行redis的cil----shell命令行
docker exec -it 运行着Rediis服务的容器ID redis-cli
# 远程连接 docker redis
docker exec -it redis_s redis-cli -h 192.168.1.100 -p 6379 -a your_password //如果有密码 使用 -a参数
RabbitMQ
# 1.下载镜像
docker pull rabbitmq:3.7.7-management
# 2.运行镜像
docker run -d --name rabbitmq3.7.7 -p 5672:5672 -p 15672:15672 -v `pwd`/data:/var/lib/rabbitmq --hostname myRabbit -e RABBITMQ_DEFAULT_VHOST=/ -e RABBITMQ_DEFAULT_USER=admin -e RABBITMQ_DEFAULT_PASS=admin df80af9ca0c9
-d 后台运行容器;
--name 指定容器名;
-p 指定服务运行的端口(5672:应用访问端口;15672:控制台Web端口号);
-v 映射目录或文件;
--hostname 主机名(RabbitMQ的一个重要注意事项是它根据所谓的 “节点名称” 存储数据,默认为主机名);
-e 指定环境变量;(RABBITMQ_DEFAULT_VHOST:默认虚拟机名;RABBITMQ_DEFAULT_USER:默认的用户名;RABBITMQ_DEFAULT_PASS:默认用户名的密码)
# 3.访问 (如下图)
http://ip:15672
账号 :admin
密码: admin
MongoDB
# 1.查看docker+MongoDB版本(图1)
docker search
# 2.下载最新的MongoDB
docker pull mongo
# 3.将镜像运行成容器
docker run -itd --name mongo -p 27017:27017 mongo --auth
## 参数说明:
-p 27017:27017 :映射容器服务的 27017 端口到宿主机的 27017 端口。外部可以直接通过 宿主机 ip:27017 访问到 mongo 的服务。
--auth:需要密码才能访问容器服务。
# 4.使用以下命令添加用户和设置密码,并且尝试连接。
$ docker exec -it mongo mongo admin
# 创建一个名为 admin,密码为 123456 的用户。
> db.createUser({ user:'admin',pwd:'123456',roles:[ { role:'userAdminAnyDatabase', db: 'admin'}]});
# 尝试使用上面创建的用户信息进行连接。
> db.auth('admin', '123456')
图1
安装vsftpd+Nignx(图片服务器)
环境搭建
通过搭建Nginx和vfstpd 实现文件服务器
# 1. 安装docker-compose . 实现对相关软件的配置
curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.4/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
# 2. 编写docker-compose.yml 配置文件
## 需要需要修改的地方的是:
## /data/ftp:/home/vsftpd/ftpuser(20行), /data/ftp 是ftp中图片存放的地址
## /data/ftp:/home/images(11行) , /data/ftp 是Nginx来对应ftp中图片存放的地址
## FTP_USER,FTP_PASS 代表ftp用户的账号和密码, 需要在Linux中提前添加用户
## 添加用户命令 a. useradd ftpuser,b. passwd ftpuser 然后输入自定义密码
## ~/pic/nginx/conf/nginx.conf(9行), 注意! 需要提前准备Nginx的配置文件nginx.conf, ~ 代表home目录
## PASV_ADDRESS: 192.168.40.21, PASV_ADDRESS后面填写的是ftp服务器的ip
----------------docker-compose.yml---------------------
version: '2'
services:
nginx-image:
image: nginx:1.15.8
ports:
- "80:80"
volumes:
- ~/pic/nginx/html:/usr/share/nginx/html
- ~/pic/nginx/conf/nginx.conf:/etc/nginx/nginx.conf
- ~/pic/nginx/logs:/var/log/nginx
- /data/ftp:/home/images
restart: always
vsftpd:
image: fauria/vsftpd
ports:
- "20:20"
- "21:21"
- "21100-21110:21100-21110"
volumes:
- /data/ftp:/home/vsftpd/ftpuser
environment:
FTP_USER: ftpuser
FTP_PASS: 1q2w3e4r
PASV_ADDRESS: 192.168.40.21
PASV_MIN_PORT: 21100
PASV_MAX_PORT: 21110
LOCAL_UMASK: 022
restart: always
-------------------------------------
# 3. 分享上面需要nginx.conf文件放在下面了
vim /home/pic/nginx/conf/nginx.conf
# 4. docker-compose执行, 需要在docker-compose.yml所在的目录下执行
docker-compose up -d
# 5. docker ps(查看容器是否执行, 下图1)
图1
上面第三步所需的nginx.conf配置文件
# root /data/ftp/, /data/ftp/代表的是我们上面配置的ftp图片存放的地址, 只需要修改这一处
location / {
root /data/ftp/;i ..... }
完整配置文件
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root /data/ftp/; # /data/ftp/代表的是我们上面配置的ftp图片存放的地址, 只需要修改这一处
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
代码测试
- 添加依赖
<!--文件上传与下载-->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
<scope>compile</scope>
</dependency>
- 工具类代码
package com.clife.common.utils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import java.io.*;
/** * ftp上传下载工具类 */
public class FtpUtil {
private static String hostname="192.168.40.21";
private static int port=21;
private static String ftpusername="ftpuser";
private static String ftppassword="ftpuser";
private static String basePath="/data/ftp";
private static String filePath="";
//日志打印
private static Logger logger = LoggerFactory.getLogger(FtpUtil.class);
/** * 文件上传封装方法 * @param sourceFileName 本地文件绝对地址,目录+文件名, eg:D:\\1.jpg * @param targetFileName 上传到ftp服务器/data/ftp/目录下的文件名 * @return * @throws FileNotFoundException */
public static boolean ftpUploadFile(String sourceFileName, String targetFileName) throws FileNotFoundException {
FileInputStream in=new FileInputStream(new File(sourceFileName));
boolean b = uploadFile(hostname, port, ftpusername, ftppassword, basePath, filePath, targetFileName, in);
return b;
}
/** * Description: 向FTP服务器上传文件 * @param host FTP服务器hostname * @param port FTP服务器端口 * @param username FTP登录账号 * @param password FTP登录密码 * @param basePath FTP服务器基础目录 * @param filePath FTP服务器文件存放路径。例如分日期存放:/2015/01/01。文件的路径为basePath+filePath * @param filename 上传到FTP服务器上的文件名 * @param input 输入流 * @return 成功返回true,否则返回false */
public static boolean uploadFile(String host, int port, String username, String password, String basePath,
String filePath, String filename, InputStream input) {
boolean result = false;
FTPClient ftp = new FTPClient();
try {
int reply;
ftp.connect(host, port);// 连接FTP服务器
logger.info("连接ftp成功...");
// 如果采用默认端口,可以使用ftp.connect(host)的方式直接连接FTP服务器
ftp.login(username, password);// 登录
logger.info("ftp用户登陆成功!!!");
reply = ftp.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftp.disconnect();
return result;
}
//切换到上传目录
if (!ftp.changeWorkingDirectory(basePath+filePath)) {
//如果目录不存在创建目录
String[] dirs = filePath.split("/");
String tempPath = basePath;
for (String dir : dirs) {
if (null == dir || "".equals(dir)) {
continue;}
tempPath += "/" + dir;
if (!ftp.changeWorkingDirectory(tempPath)) {
if (!ftp.makeDirectory(tempPath)) {
return result;
} else {
ftp.enterRemotePassiveMode();
ftp.changeWorkingDirectory(tempPath);
}
}
}
}
//设置上传文件的类型为二进制类型
ftp.setFileType(FTP.BINARY_FILE_TYPE);
//上传文件
if (!ftp.storeFile(filename, input)) {
logger.info("文件 {} 上传失败!",filename);
return result;
}
input.close();
ftp.logout();
result = true;
logger.info("文件 {} 上传成功!",filename);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ftp.isConnected()) {
try {
ftp.disconnect();
} catch (IOException ioe) {
}
}
}
return result;
}
public static void main(String[] args) {
//FileInputStream in=new FileInputStream(new File("D:\\1.jpg"));
//boolean flag = uploadFile("192.168.40.21", 21, "ftpuser", "ftpuser", "/data/ftp","", "123.png", in);
boolean flag = false;
try {
flag = ftpUploadFile("D:\\11.jpg", "6666.jpg");
System.out.println(flag);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
- 图片访问
http://192.168.40.21/6666.jpg
第八章 发布镜像到阿里云
步骤
# 1.登陆阿里云, 进入容器镜像服务(可以通过下方地址注册登录跳转到容器镜像服务)
https://cr.console.aliyun.com/cn-hangzhou/instances/repositories
# 2. 创建镜像仓库(图1)
# 3. 在docker中登陆 ,根据图2,图3中的操作指南进行操作
# 5. 将正在运行的容器创建成一个镜像(图4)
docker commit
OPTIONS说明:
-a :提交的镜像作者;
-m :提交时的说明文字;
# 4.将镜像推送到阿里云的镜像仓库(最好是根据阿里云上的操作指南)
docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/timepause/mydocker:[镜像版本号]
sudo docker push registry.cn-hangzhou.aliyuncs.com/timepause/mydocker:[镜像版本号]
# 5. 搜索镜像 ,下载镜像(图5,图6)
docker pull 复制的镜像地址
图1
图2
图3
图4
图5
图6
点击本博客相关学习视频地址
图片服务器参考博客
今天的文章docker容器技术与传统虚拟化技术的特性比较_docker容器是什么分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:http://bianchenghao.cn/75644.html