Docker介绍
Docker介绍
1、Docker是什么?
docker为什么会这么火呢?这就涉及到平时开发人员的工作,开发人员在本地可运行的项目,部署到服务器上后无法运行,可能是某些环境参数不对等问题。现在项目的部署通常是集群的方式,如果集群数量太多,运维人员需要一个个节点去部署配置,工作量太大。
总结就是一句话:解决了运行环境和配置问题软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术。
2、Docker能干嘛?
相信大家都用过VMware来运行虚拟机。下载CentOS时通常会下载一个将近4g的镜像文件。这个镜像文件中包含了一个完整的操作系统,包括内核及各类硬件的虚拟化。
而Docker容器虚拟化与宿主机使用的是同一个内核,也无需对各类硬件资源进行虚拟化,由于与宿主机共享内核,所以Docker容器比虚拟机能更快启动,通常只需要一两秒,而传统虚拟机则需要更多的时间,可能需要花上几分钟。
Docker拥有一次构建、随处运行的强大功能,有点像Java,Docker将开发者提供的项目构建完后生成一个镜像文件,这个镜像文件即可以运行,然后生成一个容器。这种功能使Docker用更快速的应用交付和部署,更便捷的升级和扩缩容,更简单的系统运维,更高效的计算资源利用等优点。正是这些优点让新浪、美团、蘑菇街等互联网企业都在使用。
3、Docker常用命令
帮助命令 :docker --help
使用此命令可以查询docker中所有命令,属于必备命令
3.1 Docker镜像命令
docker images [options] 列出本地主机上的镜像
options选项 | 作用 |
---|---|
-a | 列出本地所有的镜像(含中间映像层) |
-q | 只显示镜像ID |
--digest | 显示镜像的摘要信息 |
--no-trunc | 显示完整的镜像信息 |
docker search [options] 镜像名字
options选项 | 作用 |
---|---|
--automated | 只列出 automated build类型的镜像 |
-s | 列出收藏数不小于指定值的镜像 |
--no-trunc | 显示完整的镜像描述 |
docker pull 镜像名字[:TAG]
若不写TAG默认为latest
docker rmi [options]
options选项 | 作用 |
---|---|
(不填)+ 镜像名字ID | 删除镜像 |
-f + 镜像名ID | 删除单个镜像 |
-f + 镜像名1:TAG + 镜像名2:TAG | 删除指定的多个镜像 |
-f + $(docker images -qa) | 删除全部镜像 |
3.2 Docker容器命令
需要先有镜像才能创建容器 故先下载CentOS镜像演示 docker pull centos
命令 | 作用 |
---|---|
docker run [OPTIONS] IMAGE [COMMAND] [ARG...] | 新建并启动容器 如:docker run -it image 镜像名ID 新建并以交互式方式启动容器 |
docker ps [OPTIONS] | 列出当前所有正在运行的容器 |
exit | 停止容器并退出 |
ctrl+p+q | 容器不停止并退出 |
docker start 容器ID或容器名 | 启动容器 |
docker restart 容器ID或者容器名 | 重启容器 |
docker stop 容器id或者容器名 | 停止容器(类似电脑桌面点关机) |
docker kill 容器id或者容器名 | 强行停止容器(类似于电脑拔电源) |
docker rm 容器id | 删除已停止的容器 |
docker rm -f $(docker ps -a -q) | 一次性删除多个容器 |
先docker ps -a -q 再 xargs docker rm | 一次性删除多个容器 |
重点
命令 | 作用 |
---|---|
docker run -d 容器名 | 守护式方式启动容器 |
docker logs -f -t --tail 容器ID | -t 加入时间戳 -f 跟随最新的日志打印 --tail 数字 显示最后多少条 |
docker top 容器ID | 查看容器内运行的进程 |
docker inspect 容器ID | 查看容器内部细节 |
docker exec -it 容器ID /bin/bash | 进入正在运行的容器并以命令行交互(在容器中打开新的终端,并且可以启动新的进程) |
docker attach 容器ID | 重新进入容器(直接进入容器启动命令的终端,不会启动新进程) |
docker cp 容器ID:容器内路径 目的主机路径 | 从容器内拷贝文件到主机上 |
4、Docker镜像
4.1 镜像是什么
镜像使一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码、运行时、库、环境变量和配置文件。
4.2 联合文件系统(UnionFS)
Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同事可以将不同目录挂载到同一个虚拟文件系统下。Union文件系统是Docker镜像的基础。镜像可以通过分层来继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有的底层文件和目录。
4.3 为什么要使用分层镜像
最大的一个好处:共享资源
比如:有多个镜像都从相同的base镜像构建而来,那么宿主机只需在磁盘上保存一份base镜像,同时内存中也只需加载一份base镜像,就可以为所有容器服务,而且镜像的每一层都可以被共享。
4.4 镜像的特点
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。
4.5 Docker镜像Commit操作
docker commit 提交容器副本使之成为一个新的镜像;
docker commit -m=“提交的描述信息” -a="作者" 容器ID要创建的目标镜像名:[标签名]
若改动后commit新生成的镜像会是改动后的镜像,
5、 Docker容器数据卷
5.1 容器数据卷是什么?
前面说到Docker是将应用和环境打包成一个镜像,那容器中的数据怎么办呢,如果数据都放在容器中,当容器删除时,我们的数据就会丢失。这时候容器数据卷就出现了。
容器数据卷的作用就是实现数据的持久化,将容器中的数据同步到主机上,同时也能实现容器间的继承和容器间共享数据。
5.2 数据卷添加方式
5.2.1 直接命令添加
docker run -it -v /宿主机绝对路径目录:/容器内目录 镜像名
数据卷挂载成功后,容器内的指定目录下和宿主机指定目录下就会实现数据共享,在任意处进行修改,在另一方的目录下会有相同修改。即便容器停止退出后,主机再次修改数据,重新启动容器后,容器内部的数据也是同步的。
docker run -it -v /宿主机绝对路径目录:/容器内目录:ro 镜像名 (添加后设置容器针对该目录的权限为只读)
5.2.2 DockerFile添加
1、编写一个dockerFile脚本
2、构建该脚本(一层层构建成新的镜像)
3、新生成的镜像运行后会自动 绑定dockerFile脚本中指定的目录(与命令行方式相比)
Docker执行DockerFile的大致流程
1、docker从基础镜像运行一个容器;
2、执行一条指令并对容器做出修改;
3、执行类似docker commit的操作提交一个新的镜像层;
4、docker再基于刚提交的镜像运行一个新容器
5、执行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容器,容器是直接提供服务的。
6、DockerFile解析
6.1 保留字指令
如下代码是centos6.8的dockerfile文件
FROM scratch
MAINTAINER The CentOS Project <cloud-ops@centos.org>
ADD c68-docker.tar.xz /
LABEL name="CentOS Base Image" \
vendor="CentOS" \
license="GPLv2" \
build-date="2016-06-02"
# Default command
CMD ["/bin/bash"]
指令 | 解释 |
---|---|
FROM | 基础镜像,当前新镜像是基于哪个镜像 |
MAINTAINER | 镜像维护者的姓名和邮箱地址 |
RUN | 容器构建时需要运行的命令 |
EXPOSE | 当前容器对外暴露出的端口 |
WORKDIR | 创建容器后的工作目录(即docker run -it centos后进入的目录) |
ENV | 构建镜像过程中设置环境变量,后续可以使用如(ENV MYPATH /USER/DATA 后续使用方式为WORKDIR $MYPATH) |
ADD | 将宿主机目录下的文件拷贝进镜像且尝试自动处理url和解压tar压缩包 |
COPY | 类似ADD,拷贝文件和目录道镜像中。将从构建上下文目录中<源路径>的文件/目录复制道新的一层的镜像内的<目标路径>位置 COPY src dest; COPY ["src","dest"] |
VOLUME | 容器数据卷,在创建容器时自建容器卷,用于保存和持久化(会对应宿主机上/var/lib/docker/volumes/容器名/_data 文件夹) |
CMD | 指定一个容器启动时要运行的命令 DockerFile中可以有多个CMD指令,但只有最后一个生效,CMD会被docker run 之后的参数替换 |
ENTRYPOINT | 指定一个容器启动时要运行的命令 ENTRYPOINT的目的和CMD一样,都是在指定容器启动程序及参数(不会被替换,会在上次命令后追加) |
ONBUILD | 触发器:当构建一个被继承的DockerFile时运行命令,父镜像在被子继承后,父镜像的onbuild被触发 |
6.2 案例
6.2.1 自定义镜像mycentos
docker中的centos是精简版,很多命令都用不了,如vim, ifconfig,
现在我们想要一个可以使用vim及ifconfig命令的自定义centos镜像
DockerFile文件如下:
FROM centos
MAINTAINER aluna<wyywfcan@outlook.com>
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
6.2.2 CMD/ENTRYPOINT命令案例
1、CMD案例
首先我们看到tomcat9.0.56的dockerfile文件
#
# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh"
#
# PLEASE DO NOT EDIT IT DIRECTLY.
#
FROM openjdk:8-jdk-bullseye
ENV CATALINA_HOME /usr/local/tomcat
ENV PATH $CATALINA_HOME/bin:$PATH
RUN mkdir -p "$CATALINA_HOME"
WORKDIR $CATALINA_HOME
# let "Tomcat Native" live somewhere isolated
ENV TOMCAT_NATIVE_LIBDIR $CATALINA_HOME/native-jni-lib
ENV LD_LIBRARY_PATH ${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$TOMCAT_NATIVE_LIBDIR
# see https://www.apache.org/dist/tomcat/tomcat-9/KEYS
# see also "versions.sh" (https://github.com/docker-library/tomcat/blob/master/versions.sh)
ENV GPG_KEYS 48F8E69F6390C9F25CFEDCD268248959359E722B A9C5DF4D22E99998D9875A5110C01C5A2F6059E7 DCFD35E0BF8CA7344752DE8B6FB21E8933C60243
ENV TOMCAT_MAJOR 9
ENV TOMCAT_VERSION 9.0.56
ENV TOMCAT_SHA512 b4c2c85891e84f0fbd8fec889ef0890d68a2bfa53eb31d4d39fcf5758aa483694af7ac27533ea4bc3fc3fdae56f2fa9c018d4acf872574c0ec5e37bb443599ce
RUN set -eux; \
\
savedAptMark="$(apt-mark showmanual)"; \
apt-get update; \
apt-get install -y --no-install-recommends \
ca-certificates \
curl \
dirmngr \
gnupg \
; \
\
ddist() { \
local f="$1"; shift; \
local distFile="$1"; shift; \
local mvnFile="${1:-}"; \
local success=; \
local distUrl=; \
for distUrl in \
# https://issues.apache.org/jira/browse/INFRA-8753?focusedCommentId=14735394#comment-14735394
"https://www.apache.org/dyn/closer.cgi?action=download&filename=$distFile" \
# if the version is outdated (or we're grabbing the .asc file), we might have to pull from the dist/archive :/
"https://downloads.apache.org/$distFile" \
"https://www-us.apache.org/dist/$distFile" \
"https://www.apache.org/dist/$distFile" \
"https://archive.apache.org/dist/$distFile" \
# if all else fails, let's try Maven (https://www.mail-archive.com/users@tomcat.apache.org/msg134940.html; https://mvnrepository.com/artifact/org.apache.tomcat/tomcat; https://repo1.maven.org/maven2/org/apache/tomcat/tomcat/)
${mvnFile:+"https://repo1.maven.org/maven2/org/apache/tomcat/tomcat/$mvnFile"} \
; do \
if curl -fL -o "$f" "$distUrl" && [ -s "$f" ]; then \
success=1; \
break; \
fi; \
done; \
[ -n "$success" ]; \
}; \
\
ddist 'tomcat.tar.gz' "tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz" "$TOMCAT_VERSION/tomcat-$TOMCAT_VERSION.tar.gz"; \
echo "$TOMCAT_SHA512 *tomcat.tar.gz" | sha512sum --strict --check -; \
ddist 'tomcat.tar.gz.asc' "tomcat/tomcat-$TOMCAT_MAJOR/v$TOMCAT_VERSION/bin/apache-tomcat-$TOMCAT_VERSION.tar.gz.asc" "$TOMCAT_VERSION/tomcat-$TOMCAT_VERSION.tar.gz.asc"; \
export GNUPGHOME="$(mktemp -d)"; \
for key in $GPG_KEYS; do \
gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key"; \
done; \
gpg --batch --verify tomcat.tar.gz.asc tomcat.tar.gz; \
tar -xf tomcat.tar.gz --strip-components=1; \
rm bin/*.bat; \
rm tomcat.tar.gz*; \
command -v gpgconf && gpgconf --kill all || :; \
rm -rf "$GNUPGHOME"; \
\
# https://tomcat.apache.org/tomcat-9.0-doc/security-howto.html#Default_web_applications
mv webapps webapps.dist; \
mkdir webapps; \
# we don't delete them completely because they're frankly a pain to get back for users who do want them, and they're generally tiny (~7MB)
\
nativeBuildDir="$(mktemp -d)"; \
tar -xf bin/tomcat-native.tar.gz -C "$nativeBuildDir" --strip-components=1; \
apt-get install -y --no-install-recommends \
dpkg-dev \
gcc \
libapr1-dev \
libssl-dev \
make \
; \
( \
export CATALINA_HOME="$PWD"; \
cd "$nativeBuildDir/native"; \
gnuArch="$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)"; \
aprConfig="$(command -v apr-1-config)"; \
./configure \
--build="$gnuArch" \
--libdir="$TOMCAT_NATIVE_LIBDIR" \
--prefix="$CATALINA_HOME" \
--with-apr="$aprConfig" \
--with-java-home="$JAVA_HOME" \
--with-ssl=yes \
; \
nproc="$(nproc)"; \
make -j "$nproc"; \
make install; \
); \
rm -rf "$nativeBuildDir"; \
rm bin/tomcat-native.tar.gz; \
\
# reset apt-mark's "manual" list so that "purge --auto-remove" will remove all build dependencies
apt-mark auto '.*' > /dev/null; \
[ -z "$savedAptMark" ] || apt-mark manual $savedAptMark > /dev/null; \
find "$TOMCAT_NATIVE_LIBDIR" -type f -executable -exec ldd '{}' ';' \
| awk '/=>/ { print $(NF-1) }' \
| xargs -rt readlink -e \
| sort -u \
| xargs -rt dpkg-query --search \
| cut -d: -f1 \
| sort -u \
| tee "$TOMCAT_NATIVE_LIBDIR/.dependencies.txt" \
| xargs -r apt-mark manual \
; \
\
apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \
rm -rf /var/lib/apt/lists/*; \
\
# sh removes env vars it doesn't support (ones with periods)
# https://github.com/docker-library/tomcat/issues/77
find ./bin/ -name '*.sh' -exec sed -ri 's|^#!/bin/sh$|#!/usr/bin/env bash|' '{}' +; \
\
# fix permissions (especially for running as non-root)
# https://github.com/docker-library/tomcat/issues/35
chmod -R +rX .; \
chmod 777 logs temp work; \
\
# smoke test
catalina.sh version
# verify Tomcat Native is working properly
RUN set -eux; \
nativeLines="$(catalina.sh configtest 2>&1)"; \
nativeLines="$(echo "$nativeLines" | grep 'Apache Tomcat Native')"; \
nativeLines="$(echo "$nativeLines" | sort -u)"; \
if ! echo "$nativeLines" | grep -E 'INFO: Loaded( APR based)? Apache Tomcat Native library' >&2; then \
echo >&2 "$nativeLines"; \
exit 1; \
fi
EXPOSE 8080
CMD ["catalina.sh", "run"]
从tomcat的dockerfile文件中可以看到最后一行是 CMD ["catalina.sh", "run"]
这一命令,正是因为这一命令tomcat才能启动。
docker run -it -p 7777:8080 tomcat 此命令可以正常启动tomcat容器,
此时我们将命令更换成 docker run -it ip 7777:8080 tomcat ls -l
再次启动,这次控制台输出了tomcat 的dockerfile文件第六行定义的 WORKDIR /usr/local/tomcat文件夹中的文件信息。
docker run -it ip 7777:8080 tomcat ls -l
这个命令相当于在tomcat启动后执行了 ls -l操作。此时使用 docker ps
命令也会发现tomcat没有成功启动,因为tomcat 的 DockerFile文件中最后一行CMD ["catalina.sh", "run"]
被 ls -l命令所替换。
2、ENTRYPOINT案例
制作一个IP信息查询器
CMD版
FROM centos
RUN yum install -y curl
CMD ["curl", "-s", "http://ip.cn"]
build上述dockerfile文件 docker build -f 路径 -t myip .
成功后生成 myip镜像文件
此时执行docker run -it myip 成功后输出 当前容器的ip地址
注意:我想在此功能上添加打印http报文头内容,即实现curl -s -i http://ip.cn
,此时使用docker run myip -i
命令无法达到上述功能,上述命令其实替换了原来的CMD命令,在下面新加了一行CMD -i
。
ENTRYPOINT版
FROM centos
RUN yum install -y curl
ENTRYPOINT ["curl", "-s", "http://ip.cn"]
build上述dockerfile文件
再使用docker run myip2 -i
即可查询出http报文头,此时可以理解为更改原有命令为CMD ["curl", "-s", "-i", "http://ip.cn"]
6.2.3 自定义tomcat
1、mkdir -p /aluna/mydockerfile/tomcat9/
2、在上述目录touch c.txt
3、cp apache-tomcat-9.0.8.tar.gz 上述路径(将tomcat和jdk复制入上述路径)
4、vim DockerFile
FROM centos
MAINTAINER aluna<wyywfcan@outlook.com>
#把宿主机当前上下文的c.txt拷贝到容器/usr/local/路径下
COPY c.txt /usr/local/cincontainer.txt
#把Java和tomcat添加到容器中
ADD jdk-8u171-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.8.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_171
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.8
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.8
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.8/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.8/bin/logs/catalina.out
5、docker build DockerFile -t tomcat9
6、docker images 查看是否创建成功
7、docker run -d -p 9080:8080 --name myt9 -v /aluna/mydockerfile/tomcat9/test:/usr/local/apache-tomcat-9.0.9/webapps/test -v /aluna/mydockerfile/tomcat9/tomcat9logs/:/usr/local/apache-tomcat-9.0.8/logs --privileged=true tomcat9
(后台启动指定主机端口9080映射容器端口8080,名字取myt9,建立两个两个容器卷并分配写权限)
8、将服务发布至/aluna/mydockerfile/tomcat9/test目录下