解决了运行环境和配置问题软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术。
问什么会出现docker
一款产品从开发到上线,从操作系统,到运行环境,再到应用配置。作为开发+运维之间的协作我们需要关心很多东西,这也是很多互联网公司都不得不面对的问题,特别是各种版本的迭代之后,不同版本环境的兼容,对运维人员都是考验。
Docker之所以发展如此迅速,也是因为它对此给出了一个标准化的解决方案。
环境配置如此麻烦,换一台机器,就要重来一次,费力费时。很多人想到,能不能从根本上解决问题,软件可以带环境安装?也就是说,安装的时候,把原始环境一模一样地复制过来。开发人员利用 Docker 可以消除协作编码时“在我的机器上可正常工作”的问题。
docker的理念
Docker是基于Go语言实现的云开源项目。
Docker的主要目标是“Build,Ship and Run Any App,Anywhere”,也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的APP(可以是一个WEB应用或数据库应用等等)及其运行环境能够做到“一次封装,到处运行”。
由于前面虚拟机存在这些缺点,Linux 发展出了另一种虚拟化技术:Linux 容器(Linux Containers,缩写为 LXC)。
Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离。有了容器,就可以将软件运行所需的所有资源打包到一个隔离的容器中。容器与虚拟机不同,不需要捆绑一整套操作系统,只需要软件工作所需的库资源和设置。系统因此而变得高效轻量并保证部署在任何环境中的软件都能始终如一地运行。
说明:
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或者更高版本。
Docker 镜像(Image)就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。
Docker 利用容器(Container)独立运行的一个或一组应用。容器是用镜像创建的运行实例。
它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。
可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
容器的定义和镜像几乎一模一样,也是一堆层的统一视角,唯一区别在于容器的最上面那一层是可读可写的。
仓库(Repository)是集中存放镜像文件的场所。
仓库(Repository)和仓库注册服务器(Registry)是有区别的。仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。
仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
最大的公开仓库是 Docker Hub(https://hub.docker.com/),
存放了数量庞大的镜像供用户下载。国内的公开仓库包括阿里云 、网易云 等
需要正确的理解仓储/镜像/容器这几个概念:
Docker 本身是一个容器运行载体或称之为管理引擎。我们把应用程序和配置依赖打包好形成一个可交付的运行环境,这个打包好的运行环境就似乎 image镜像文件。只有通过这个镜像文件才能生成 Docker 容器。image 文件可以看作是容器的模板。Docker 根据 image 文件生成容器的实例。同一个 image 文件,可以生成多个同时运行的容器实例。
yum install -y epel-release
cat /etc/redhat-release
yum -y install gcc
yum -y install gcc-c++
卸载旧版本(查看官网最新卸载方式)
yum -y remove docker docker-common docker-selinux docker-engine
安装需要的软件包
yum install -y yum-utils device-mapper-persistent-data lvm2
设置stable镜像仓库
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
更新yum软件包索引
yum makecache fast
安装DOCKER CE
yum -y install docker -ce
启动docker
systemctl start docker
测试
docker version
docker run hello-world
mkdir -p /etc/docker
vim /etc/docker/daemon.json
#网易云 {"registry-mirrors": ["http://hub-mirror.c.163.com"] }
#阿里云 {"registry-mirrors": ["https://{自已的编码}.mirror.aliyuncs.com"]}
systemctl daemon-reload
systemctl restart docker
启动docker后,测试运行
docker run hello-world
输出这段提示以后,hello world就会停止运行,容器自动终止。
docker是怎么工作的
Docker是一个Client-Server结构的系统,Docker守护进程运行在主机上, 然后通过Socket连接从客户端访问,守护进程从客户端接受命令并管理运行在主机上的容器。 容器,是一个运行时环境,就是我们前面说到的集装箱。
为什么docker比vm快
docker version
docker info
docker --help
docker images
docker search
docker search [OPTIONS] 镜像名字
OPTIONS说明:
--no-trunc
:只显示镜像完整描述-s
:列出收藏数不小于指定值的镜像--automated
:只列出automated build类型的镜像docker pull
下载镜像docker pull 镜像名字[:TAG]
docker rmi
删除镜像docker run [OPTIONS] IMAGE [COMMAND] [AGE.....]
OPTIONS说明(常用):有些是一个减号,有些是两个减号
–name=“容器新名字”: 为容器指定一个名称;
-d: 后台运行容器,并返回容器ID,也即启动守护式容器;
-i:以交互模式运行容器,通常与 -t 同时使用;
-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;
-P: 随机端口映射;
-p: 指定端口映射,有以下四种格式
ip:hostPort:containerPort
ip::containerPort
hostPort:containerPort
containerPort
docker ps [OPTIONS]
OPTIONS参数说明:
-a :列出当前所有正在运行的容器+历史上运行过的
-l :显示最近创建的容器。
-n:显示最近n个创建的容器。
-q :静默模式,只显示容器编号。
–no-trunc :不截断输出。
exit
// 强行停止退出docker start 容器名或者ID
docker restart 容器名称或ID
docker stop 容器名称或ID
docker kill 容器名称或者ID
docker rm 容器ID
一次性删除多个
docker rm -f $(docker ps -a -q)
docker run -d 镜像名
使用镜像centos:latest以后台模式启动一个容器docker run -d centos
问题:然后docker ps -a 进行查看, 会发现容器已经退出;很重要的要说明的一点: Docker容器后台运行,就必须有一个前台进程.
容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail),就是会自动退出的。
这个是docker的机制问题,比如你的web容器,我们以nginx为例,正常情况下,我们配置启动服务只需要启动响应的service即可。例如service nginx start
但是,这样做,nginx为后台进程模式运行,就导致docker前台没有运行的应用,
这样的容器后台启动后,会立即自杀因为他觉得他没事可做了.
所以,最佳的解决方案是,将你要运行的程序以前台进程的形式运行
docker logs -f -t 容器ID
-t 是加入时间戳
-f 跟随最新的日志打印
–tail 数字 显示最后多少条
docker top 容器ID
docker inspect 容器ID
docker exec -it 容器ID /bin/bash/
docker attach 容器ID
docker cp 容器ID:容器内路径 目的主机路径
docker commit [OPTIONS] 容器ID 镜像名[:TAR]
OPTIONS说明
-a 指定作者名
-m 描述信息
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的理念:
docker run -it -v 宿主机绝对路径:容器内路径 镜像名
查看是否挂载成功:docker inspect 镜像ID
FROM centos
VOLUME ["/dataVolumeContainer1","/dataVolumeContainer2"]
CMD echo "finished,--------success1"
CMD /bin/bash
可以在DockerFile中使用Volume指令来给一个镜像添加一个或多个数据卷
docker build [OPTIONS] PATH | URL | -
注意,命令结尾有个点 .
4. 运行容器然后查看数据卷
5. 主机对应的卷目录
docker inspect 容器ID
主机默认地址是/var/lib/docker/volumes/
dockerFile数据卷主机目录不能指定,是随机生成的。
两个容器之间相互共享数据。
命名的容器挂载数据卷,其它容器通过挂载这个(父容器)实现数据共享,挂载数据卷的容器,称之为数据卷容器。
[root@localhost dockerFile]# docker attach dc1
[root@13a3db6a7192 /]# ls
bin dataVolumeContainer1 dataVolumeContainer2 dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@13a3db6a7192 /]# cd dataVolumeContainer2/
[root@13a3db6a7192 dataVolumeContainer2]# ls
[root@13a3db6a7192 dataVolumeContainer2]# touch dc1.txt
[root@13a3db6a7192 dataVolumeContainer2]# ls
dc1.txt
[root@localhost dockerFile]# docker run -it --name dc2 --volumes-from dc1 gg/centos
[root@09c2ce005191 /]# ls
bin dataVolumeContainer1 dataVolumeContainer2 dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
[root@09c2ce005191 /]# ls dataVolumeContainer2/
dc1.txt
[root@09c2ce005191 /]#
[root@localhost dockerFile]# docker run -it --name dc3 --volumes-from dc1 gg/centos
[root@b0e92d08bdf8 /]# ls dataVolumeContainer2
dc1.txt
[root@b0e92d08bdf8 /]#
[root@09c2ce005191 dataVolumeContainer2]# touch dc2.txt
[root@09c2ce005191 dataVolumeContainer2]# ls
dc1.txt dc2.txt
[root@09c2ce005191 dataVolumeContainer2]#
dc3
[root@b0e92d08bdf8 /]# cd dataVolumeContainer2
[root@b0e92d08bdf8 dataVolumeContainer2]# touch dc3.txt
[root@b0e92d08bdf8 dataVolumeContainer2]# ls
dc1.txt dc2.txt dc3.txt
[root@b0e92d08bdf8 dataVolumeContainer2]#
此时dc1
[root@localhost dockerFile]# docker attach dc1
[root@13a3db6a7192 dataVolumeContainer2]# ls
dc1.txt dc2.txt dc3.txt
[root@13a3db6a7192 dataVolumeContainer2]#
可以看到三个容器数据卷内容是同步的
[root@localhost dockerFile]# docker rm dc1
dc1
[root@localhost dockerFile]# docker attach dc2
[root@09c2ce005191 dataVolumeContainer2]# touch dc2_del1.txt
[root@09c2ce005191 dataVolumeContainer2]# ls
dc1.txt dc2.txt dc2_del1.txt dc3.txt
[root@09c2ce005191 dataVolumeContainer2]#
[root@localhost dockerFile]# docker attach dc3
[root@b0e92d08bdf8 dataVolumeContainer2]# ls
dc1.txt dc2.txt dc2_del1.txt dc3.txt
[root@b0e92d08bdf8 dataVolumeContainer2]#
删除父,子容器仍然可以同步。
[root@localhost volumes]# docker rm dc2
dc2
[root@localhost volumes]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b0e92d08bdf8 gg/centos "/bin/sh -c /bin/bash" 17 minutes ago Up 16 minutes dc3
[root@localhost volumes]#
[root@localhost dockerFile]# docker attach dc3
[root@b0e92d08bdf8 dataVolumeContainer2]# ls
dc1.txt dc2.txt dc2_del1.txt dc3.txt
dc3仍然可以访问。
总结
容器之间的配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止。
Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。
构建镜像的三个步骤:1. 编写DockerFile文件;2. docker build; 3. docker run
从应用软件角度来看,dockerFile,docker镜像与docker容器分别代表软件的三个不同阶段:
dockerFile面向开发,docker镜像成为交付标准,docker容器涉及到部署与运维。
FROM
:基础镜像,当前新镜像是基于哪个镜像的MAINTAINER
:镜像维护者的姓名和邮件地址RUN
:容器构建时要运行的命令EXPOSE
:当前容器对外暴露出的端口WORKDIR
:指定在创建容器后,终端默认登录进来的工作目录ENV
:用来构建镜像过程中的环境变量;这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面指定了环境变量前缀一样;也可以在其它指令中直接使用这些环境变量。比如:WORKDIR $MY_PATHADD
:将宿主机目录下的文件拷贝到镜像且ADD命令会自动处理URL和解压tar文件COPY
:类似ADD,copy目录或文件到镜像中。只是单纯的copy;VOLUME
:容器数据卷,用于数据保存和持久化工作CMD
:指定一个容器启动时要运行的命令。DockerFile中可以有多个CMD命令,但只有最后一个有效,CMD会被docker run之后的参数替换ENTRYPOINT
:指定一个容器启动时要运行的命令,ENTRYPOINT的目的和CMD是一样的,都是在指定容器启动程序以及参数ONBULID
:当构建一个被继承的DockerFile时运行命令,父镜像在被子继承后父镜像的onbuild被触发[root@localhost /]# cd /tmp/dockerFile/
[root@localhost dockerFile]# vi DockerFile
[root@localhost dockerFile]# cat DockerFile
FROM centos
MAINTAINER guggugugu
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "success-----------------ok"
CMD /bin/bash
[root@localhost dockerFile]#
docker build -f DockerFile -t mycentos:1.0 .
docker run -it mycentos:1.0
docker history mycentos:1.0
[root@localhost docker_tomcat]# pwd
/tmp/docker_tomcat
[root@localhost docker_tomcat]# ll
总用量 150768
drwxr-xr-x. 9 root root 220 9月 27 23:53 apache-tomcat-9.0.38
-rw-r--r--. 1 root root 11264531 9月 27 23:23 apache-tomcat-9.0.38.tar.gz
-rw-r--r--. 1 root root 0 9月 27 23:45 c.txt
drwxr-xr-x. 8 10143 10143 273 6月 18 14:59 jdk1.8.0_261
-rw-r--r--. 1 root root 143111803 9月 27 23:54 jdk-8u261-linux-x64.tar.gz
[root@localhost docker_tomcat]# cat dockerfile
FROM centos
MAINTAINER gu.com
COPY c.txt /usr/local/cincontainer.txt
ADD jdk-8u261-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.38.tar.gz /usr/local/
RUN yum -y install vim
ENV MYPATH /usr/local/
WORKDIR $MYPATH
ENV JAVA_HOME /usr/local/jdk1.8.0_261
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.38
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.38
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
EXPOSE 8080
CMD /usr/local/apache-tomcat-9.0.38/bin/startup.sh && tail -f /usr/local/apache-tomcat-9.0.38/logs/catalina.out
docker build -f dockerfile -t mytomcat
docker run -it -p 9080:8080 --name mycat9 -v /tmp/docker_tomcat/test:/usr/local/apache-tomcat-9.0.38/webapps/test -v /tmp/docker_tomcat/logs/:/usr/local/apache-tomcat-9.0.38/logs --privileged=true mytomcat
Docker挂载主机目录Docker访问出现cannot open directory .: Permission denied
解决办法:在挂载目录后多加一个–privileged=true
参数即可