容器不需要捆绑一整套操作系统,它只需要满足软件运行的最小内核就行了。
与传统的虚拟机相比,docker优势体现在启动速度快,占用体积小
是一个只读的模板,一个文件。镜像可以用来创建Docker容器,一个镜像可以创建很多容器。
它也相当于一个root文件系统。比如官方镜像centos7就包含了完成的一套centos7最小系统的root文件系统。
又等同于容器的‘源代码’,docker镜像文件类似于java的类模板,而docker容器实例类似于java中new出来的实例对象
容器是用镜像创建的运行实例,是一个服务。
就像java中的类和实例对象一样,镜像是静态的定义,容器是镜像运行时的实体。
容器为镜像提供了一个标准的和隔离的运行环境,它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。
可以把容器看做一个简单的linux环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
是集中存放镜像文件的地方。
docker公司提供的官方registry被称为docker hub,存放各种镜像模板的地方。
# 启动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
docker search tomcat
docker pull 镜像名字
docker system df
docker rmi 镜像名称/镜像id
docker save -o redis.tar redis
docker load -i redis.tar
docker run [options] images [command] [arg...]
options可选参数:
比如我们想访问redis,但是redis在docker内部,所以我们必须通过一个端口访问docker,docker拿着这个端口对应的端口去内部访问。
写-p 6379:6380
,就是docker内部redis暴露的端口是6380,而宿主机对外暴露的端口是6379,要想访问docker内的redis,我们需要访问宿主机的6379端口
可以进入到启动的容器内部
[root@yhx ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest ba6acccedd29 5 months ago 72.8MB
hello-world latest feb5d9fea6a5 5 months ago 13.3kB
[root@yhx ~]# docker run -it ubuntu /bin/bash
root@7a24369c5aa1:/# ls
bin boot dev etc home lib lib32 lib64 libx32 media mnt opt proc root run sbin srv sys tmp usr var# 给容器指定名称
[root@yhx ~]# docker run --name=myU1 ubuntu
docker ps [options]
options可选项:
如何从容器内部退出?
[root@yhx ~]# docker run -it --name=myU2 ubuntu
root@74bc8360c83d:/# exit
exit
[root@yhx ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@yhx ~]# docker run -it --name=myU3 ubuntu
root@0de743d939f5:/#
[root@yhx ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0de743d939f5 ubuntu "bash" 8 seconds ago Up 7 seconds myU3
[root@yhx ~]#
# 重启容器
docker restart id/容器名
# 停止容器
docker stop id/容器名
# 强制停止容器
docker kill id/容器名
# 删除已经停止的容器
docker rm 容器名称/id
# 强制删除容器
docker rm -f 容器名称/id
docker run -d 容器名
我们尝试启动一下centos镜像:
[root@yhx docker]# docker run -d --name=centos8 centos
3debce674ad8a24f55adef4c874b09a13d5c9b7517eddd5ab39edee46c187c93
[root@yhx docker]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3debce674ad8 centos "/bin/bash" 3 seconds ago Exited (0) 2 seconds ago centos8
[root@yhx docker]#
通过docker ps -a
命令我们可以看到已经停止的容器。
于是疑惑产生了, -d 是保证容器在后台运行,为什么我的容器停止运行了呢?
前面提到过, docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
中有一个 COMMAND 参数,容器启动后会执行 COMMAND命令,它的默认值为 /bin/bash。也就是说容器在后台启动成功后,执行了 COMMAND 命令后直接关闭了。
了解到该原理后,我们可以通过在 docker run -d 后增加一个驻留在进程中长期运行的命令就可以保证容器不关闭了。
[root@yhx docker]# docker run -d --name=centos9 centos tail -f /dev/null
8da9a8358b679f83dac1a8a98b8620e60d37e3c1b8680483bd3448e4de1f12b5
[root@yhx docker]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8da9a8358b67 centos "tail -f /dev/null" 3 seconds ago Up 2 seconds centos9
3debce674ad8 centos "/bin/bash" 3 minutes ago Exited (0) 3 minutes ago centos8
[root@yhx docker]#
# 查看容器日志
docker logs 容器id
# 查看容器内运行的进程
docker top 容器id
# 查看容器内部细节
docker inspect 容器id
# 重新进入正在运行的容器
docker exec -it 容器id bashShell
# 重新进入正在运行的容器, 不建议使用
docker attach 容器id
区别:
# 从容器中转出
docker cp 容器id:容器目录地址 主机目录地址
# 例
docker cp 371ce72fa7f5:/usr/local/a.txt /home/aaa.txt
# 导出
docker export 容器id > 文件名.tar
# 导入
cat 文件名.tar | docker import -镜像用户/镜像名:版本号
[root@yhx ~]# docker export 1be58e734dc9 > a.tar
[root@yhx ~]# ls
a.tar
[root@yhx ~]# cat a.tar | docker import - a/a
sha256:c4b611df9300f0cddbfe0a1fb61cd4fabc40bf8c7478b7bfbb5d5c5a83b23477
[root@yhx ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
a/a latest c4b611df9300 11 seconds ago 109MB
redis latest 7614ae9453d1 2 months ago 113MB
ubuntu latest ba6acccedd29 5 months ago 72.8MB
hello-world latest feb5d9fea6a5 5 months ago 13.3kB
[root@yhx ~]#
docker commit 提交容器副本使之成为一个新的镜像
docker commit -m="提交的描述信息" -a="作者" 容器id 要创建的目标镜像名:[标签名]
进入ubuntu的镜像,可以看到目前不带vim命令:
root@a893f307cfa1:/# vim lib
bash: vim: command not found
安装vim:
apt-get update
apt-get -y install vim
提交我们具备vim命令的ubuntu容器:
[root@yhx ~]# docker commit -m="with vim" -a="yhx" a893f307cfa1 with-vim/with-vim:1.0
sha256:9b6363fb0c60770935be5327e94c19c0ae550bc478a8df7ef4c1978f34ad3e77
[root@yhx ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
with-vim/with-vim 1.0 9b6363fb0c60 6 seconds ago 175MB
a/a latest c4b611df9300 About an hour ago 109MB
tomcat latest fb5657adc892 2 months ago 680MB
redis latest 7614ae9453d1 2 months ago 113MB
ubuntu latest ba6acccedd29 5 months ago 72.8MB
hello-world latest feb5d9fea6a5 5 months ago 13.3kB
[root@yhx ~]#
接下来启动我们新建的镜像,就可以包括vim功能了
从远程仓库拉去tomcat,可以看到镜像是一层一层下载的:
docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统叫UnionFS。
是一种分层,轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。Union文件系统是Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件盒目录。
bootfs(boot file system)主要包含bootloader和kernel,bootloader主要是引导加载kernel,linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs。这一层与我们典型的linux系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
rootfs(root file system),在bootfs之上。包含的就是典型linux系统中的/dev、/bin、/etc等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如ubuntu、centos等。
为什么平常我们虚拟机的centos好几个G,而docker才200M?
对于一个精简的os,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就行了。
可以共享资源,方便复制迁移,方便复用。
比如说有多个镜像都从相同的base镜像构建而来,那么Docker Host只需在磁盘上保存一份base镜像;同时内存中也只需加载一份base镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
docker中的镜像分层,支持通过扩展现有的镜像,创建新的镜像。类似java继承于一个base基础类,自己再按需扩展。
新镜像是从base镜像一层一层叠加生成的。没安装一个软件,就在现有镜像的基础上增加一层。
卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因为能够绕过union file system提供一些用于持续存储或共享数据的特性。
卷的设计目的就是数据持久化,完全独立于容器的生命周期,因为docker不会在容器删除时删除其挂载的数据卷。
将容器的重要数据备份持久化到主机中,防止不小心删除容器导致数据丢失
docker inspect 容器id
docker run [其他的一些可选参数] -v /宿主机绝对路径目录:/容器内目录 --privileged=true 镜像名
例:
# 其中-d -p不多说
# -v代表将后面‘:’前面的路径即宿主机的路径和‘:’后面的路径即容器内的路径实现了数据共享
# --privileged=true表示放开权限
# registry表示启动后的容器名
docker run -d -p 5000:5000 -v /zzyyuser/myregistry:/tmp/registry --privileged=true registry
默认情况,即不指定关联路径的时候,仓库被创建在容器的/var/lib/registry目录下。
此处建议自行用容器卷映射,方便宿主机联调。
# rw:可读可写
# ro:只读即read only,宿主机可以写入数据,容器只能读取,不能修改目录内容
# 如果不加,默认是rw即可读可写
docker run -it --privileged=true -v /宿主机目录:/容器内目录:rw/ro 镜像名
容器1完成和宿主机的映射,容器2继承容器1的卷:
docker run -it --privileged=true --volumes-from 容器1 --name 容器2 ubuntu
[root@yhx ~]# docker run -it --privileged=true --volumes-from u1 --name u2 ubuntu
root@fd1b6d17de39:/# cd /tmp/
root@fd1b6d17de39:/tmp# ls
docker_data
root@fd1b6d17de39:/tmp# cd docker_data/
root@fd1b6d17de39:/tmp/docker_data# ls
study.txt
root@fd1b6d17de39:/tmp/docker_data#
如果容器1挂了,会不会对容器2造成影响?
答案是不会,所以我的理解虽然这里是继承,但是继承的只是配置,也就是容器2已经直接连到了宿主机。
dockerfile是用来构建docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。
FROM:基础镜像,当前新镜像是基于哪个镜像的,制定一个已经存在的镜像作为模板,第一条必是from
MAINTAINER:镜像维护者的姓名和邮箱地址
RUN:容器构建时需要执行的命令。run是在docker build时运行。两种格式:
EXPOSE:当前容器对外暴露的端口
WORKDIR:指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点。即通过docker run -it 镜像id
启动后,进入到容器内部后的目录地址
USER:指定该镜像以什么样的用户去执行,如果不指定,默认是root
ENV:用来在构建镜像过程中,设置环境变量。比如设置 ENV MY_PATH /usr/mytest
,这个环境变量可以在后续的任何RUN指令中使用,这就如同在命令前面置顶了环境变量前缀一样;也可以在其他指令中直接使用这些环境变量。接着就可以直接使用WORKDIR $MY_PATH
VOLUME:容器数据卷,用于数据保存和持久化工作
ADD:将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
COPY:类似ADD,拷贝文件和目录到镜像中。将从构建上下文目录中<源路径>的文件/目录复制到新的一层的镜像内的<目标路径>位置
CMD:CMD指令的格式和RUN相似
ENTRYPOINT:也是用来指定一个容器启动时要运行的命令。类似CMD指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当做参数送给ENTRYPOINT指令指定的程序。
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
""
先pull官方版本centos镜像,拉下来的镜像并不包含vim,ifconfig,jdk8等内容,我们希望自己能制作一个镜像并拥有以上功能。
下载一个jdk和Dockerfile放在一起
# 最新的centos8不维护了有些问题,这里用的centos7
FROM centos:7.2.1511
MAINTAINER yhxENV MYPATH /usr/local
WORKDIR $MYPATH# 安装vim编辑器
RUN yum -y install vim
# 安装ifconfig命令及查看网络ip
RUN yum -y install net-tools
#安装java17及lib库
RUN mkdir /usr/local/java
#ADD 是相对路径jar,把jdk添加到容器中,安装包必须要和Dockerfile文件在同一位置
ADD jdk-17_linux-x64_bin.tar.gz /usr/local/java
#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk-17.0.2
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jarL$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATHEXPOSE 80CMD echo $MYPATH
CMD echo "success .......OK"
CMD /bin/bash
# 注意后面有个点
# 此时t:--target string Set the target build stage to build.
docker build -t 新镜像名称:TAG .# 此处:
[root@yhx studyDockerfile]# docker build -t centosjava17:1.0 .
使用docker的maven插件:
com.spotify docker-maven-plugin 0.4.13 http://192.168.0.237:2375 materials_center/comm-public latest ${pom.basedir} E:\134client
/ ${project.build.directory} ${project.build.finalName}.jar
# 基础镜像使用
FROM openjdk:8u212-jre
# 将jar包添加到容器中的指定目录下
COPY cwms-1.0.0.jar /home/logistics-cloud/project/cwms-1.0.0.jar
#设置系统编码
ENV LANG C.UTF-8
ENTRYPOINT ["java", "-Xmx1256m", "-jar", "/home/logistics-cloud/project/cwms-1.0.0.jar"]
docker启动后,会产生一个名为docker0的虚拟网桥
为每个容器分配、设置ip等,并将容器连接到一个docker0;
虚拟网桥,默认为该模式
Docker服务默认会创建一个docker0网桥(其中有一个docker0的内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker默认指定了docker0接口的IP地址和子网掩码,让主机和容器之间可以通过相互通信。
容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口与外界进行通信,不再需要额外进行NAT转换
容器有独立的NetWork namespace,但并没有对其进行任何网络设置,如分配veth pair和网桥连接、IP等
禁用网络功能,只有lo标识(就是127.0.0.1表示本地循环)
在none模式下,并不为docker容器进行任何网络配置。也就是说,这个docker容器没有网卡、ip、路由等信息,只有一个lo,需要我们自己为docker容器添加网卡、配置ip等
新创建的容器不会创建自己的网卡和配置自己的IP,而是和一个指定的容器共享IP,端口范围等
两个容器除了网络方面,其他的如文件系统,进程列表等还是隔离的。
docker-comppse是docker官方的开源项目,负责实现对docker容器集群的快速编排。
Compose是Docker公司推出的一个工具软件,可以管理多个Docker容器组成一个应用。你需要定义一个YAML格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器
解析第一个服务的编写,等同于我们单独启动的命令:
docker run -d -p 9700:9700 -v /home/common-business/crea-suytest-project/logs:/log
--network host --name crea-suytest crea_cloud/crea-suytest:latest
# docker-compose 版本,现在我们基本上都用3
version: '3'services: #本工程的服务配置列表crea-suytest: #spring boot的服务名,服务名自定义image: crea_cloud/crea-suytest:latest #指定基于crea_cloud/integrity-admin:latest镜像为基础镜像来构建镜像# build: #基于Dockerfile文件构建镜像时使用的属性# context: . #代表当前目录,也可以指定绝对路径[/path/test/Dockerfile]或相对路径[../test/Dockerfile],尽量放在当前目录,便于管理# dockerfile: Dockerfile #指定Dockerfile文件名。如果context指定了文件名,这里就不用本属性了container_name: crea-suytest #spring boot服务启动后实例的名称volumes: #挂载属性- "/home/common-business/crea-suytest-project/logs:/log"# command: # 容器启动后默认执行的命令 主要目的是在执行容器时提供默认值。这些将在入口点之后被附加到入口的参数。# - "--crea-monitor-admin=192.168.0.61"#- "--crea-gateway=192.168.0.61"#- "--nacos.url=192.168.0.61:8001"#- "--mysql.url=192.168.0.63"#- "--redis.url=192.168.0.63"#- "--redis.password=qwer123!@#."#- "--mysql.username=db_manager"#- "--mysql.password=db_manager_crea"#- "--mysql.port=3306"#- "--fastdfs.url=192.168.0.243"#- "--rabbitmq.url=192.168.0.63"#- "--storage.url=192.168.0.243"#- "--server.url=192.168.0.61"#- "--seata.url=192.168.0.61"environment:#设置容器的环境变量- "TZ=Asia/Shanghai" #这里设置容器的时区为亚洲上海 解决了容器的时区问题- "encryption=false"env_file: #这个文件可以设置 Compose 的变量,在 docker-compose.yml 中可以定义一个专门存放变量的文件 运行容器时,Compose 文件中定义的环境变量优先- suytest.env#类似于CMD指令的功能,用于为容器指定默认的运行程序,从而使得容器像是一个单独的可执行文件entrypoint: java -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/heap-dunp/crea-suytest.hprof -XX:-OmitStackTraceInFastThrow -jar /home/project/crea-suytest-1.0.0.jarports:#映射端口属性- 9700:9700 #建议使用字符串格式,指定宿主机端口映射到本容器的端口restart: on-failure #是否随docker服务启动重启 network_mode: "host" #设置网络模式 默认 bridge ,host 主机模式 # depends_on: # 取决于下面的镜像,也就是先启动下一个镜像,再启动这个镜像# - crea-suytest-mobilecrea-suytest-mobile: # 第二个微服务image: crea_cloud/crea-suytest-mobile:latestcontainer_name: crea-suytest-mobilevolumes:- "/home/common-business/crea-suytest-project/logs:/log"environment:- "TZ=Asia/Shanghai"- "encryption=false"env_file:- suytest.enventrypoint: java -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/heap-dunp/crea-suytest-mobile.hprof -XX:-OmitStackTraceInFastThrow -jar /home/project/crea-suytest-mobile-1.0.0.jarports:- 9701:9701restart: on-failurenetwork_mode: "host"crea-lottery: # 第三个微服务image: crea_cloud/crea-lottery:latestcontainer_name: crea-lotteryvolumes:- "/home/common-business/crea-suytest-project/logs:/log"environment:- "TZ=Asia/Shanghai"- "encryption=false"env_file:- suytest.enventrypoint: java -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/heap-dunp/crea-lottery.hprof -XX:-OmitStackTraceInFastThrow -jar /home/project/crea-lottery-1.0.0.jarports:- 9702:9702restart: on-failurenetwork_mode: "host"
其中的suytest.env文件是相关连接配置:
[root@localhost crea-suytest-project]# cat suytest.env
crea-monitor-admin=192.168.0.61
crea-gateway=192.168.0.61
nacos.url=192.168.0.61:8001
mysql.url=192.168.0.63
redis.url=192.168.0.63
redis.password=123
mysql.username=123
mysql.password=123
mysql.port=3306
fastdfs.url=192.168.0.243
rabbitmq.url=192.168.0.63
storage.url=192.168.0.243