-d 后台运行
–name 给容器命名
-p 宿主机端口:容器内部端口
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker run -d --name nginx01 -p 3344:80 nginx
aa664b0c8ed98f532453ce1c599be823bcc1f3c9209e5078615af416ccb454c2
#4. 查看正在启动的镜像
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
75943663c116 nginx “nginx -g 'daemon of…” 41 seconds ago Up 40 seconds 0.0.0.0:82->80/tcp nginx00
#5. 进入容器
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker exec -it nginx01 /bin/bash #进入
root@aa664b0c8ed9:/# whereis nginx #找到nginx位置
nginx: /usr/sbin/nginx /usr/lib/nginx /etc/nginx /usr/share/nginx
root@aa664b0c8ed9:/# cd /etc/nginx/
root@aa664b0c8ed9:/etc/nginx# ls
conf.d fastcgi_params koi-utf koi-win mime.types modules nginx.conf scgi_params uwsgi_params win-utf
#6. 退出容器
root@aa664b0c8ed9:/etc/nginx# exit
exit
#7. 停止容器
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
aa664b0c8ed9 nginx “nginx -g 'daemon of…” 10 minutes ago Up 10 minutes 0.0.0.0:3344->80/tcp nginx01
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker stop aa664b0c8ed9
分析图:
我们服务器配置安全组和放行端口后,我们可以访问到宿主机的3344端口,然而我们的容器相当于通过虚拟化镜像,依赖服务器内核,生成的小型linux服务器,而nginx是在我们的容器当中,想要访问需要配置映射关系,访问宿主机的3344端口的时候,自动映射到容器中nginx对应的80端口!
安装成功
问题:我们每次改动nginx配置文件,都需要进入容器内部?十分麻烦,我要是可以在容器外部提供一个映射路径,达到在容器外部修改文件名,容器内部就可以自动修改?-v 数据卷 技术
2.Docker安装Tomcat
下载 tomcat9.0
之前的启动都是后台,停止了容器,容器还是可以查到, docker run -it --rm 镜像名 一般是用来测试,用完就删除
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker run -it --rm tomcat:9.0
–rm Automatically remove the container when it exits 用完即删
#下载 最新版
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker pull tomcat
#查看下载的镜像
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker images
#以后台方式,暴露端口方式,启动运行
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker run -d -p 8080:8080 --name tomcat01 tomcat
#测试访问有没有问题
curl localhost:8080
#根据容器id进入tomcat容器
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker exec -it 645596565d3f /bin/bash
root@645596565d3f:/usr/local/tomcat#
#查看tomcat容器内部内容:
root@645596565d3f:/usr/local/tomcat# ls -l
total 152
-rw-r–r-- 1 root root 18982 May 5 20:40 BUILDING.txt
-rw-r–r-- 1 root root 5409 May 5 20:40 CONTRIBUTING.md
-rw-r–r-- 1 root root 57092 May 5 20:40 LICENSE
-rw-r–r-- 1 root root 2333 May 5 20:40 NOTICE
-rw-r–r-- 1 root root 3255 May 5 20:40 README.md
-rw-r–r-- 1 root root 6898 May 5 20:40 RELEASE-NOTES
-rw-r–r-- 1 root root 16262 May 5 20:40 RUNNING.txt
drwxr-xr-x 2 root root 4096 May 16 12:05 bin
drwxr-xr-x 1 root root 4096 May 21 11:04 conf
drwxr-xr-x 2 root root 4096 May 16 12:05 lib
drwxrwxrwx 1 root root 4096 May 21 11:04 logs
drwxr-xr-x 2 root root 4096 May 16 12:05 native-jni-lib
drwxrwxrwx 2 root root 4096 May 16 12:05 temp
drwxr-xr-x 2 root root 4096 May 16 12:05 webapps
drwxr-xr-x 7 root root 4096 May 5 20:37 webapps.dist
drwxrwxrwx 2 root root 4096 May 5 20:36 work
root@645596565d3f:/usr/local/tomcat#
#进入webapps目录
root@645596565d3f:/usr/local/tomcat# cd webapps
root@645596565d3f:/usr/local/tomcat/webapps# ls
root@645596565d3f:/usr/local/tomcat/webapps#
发现问题:1、linux命令少了。 2.webapps目录为空
原因:阿里云镜像的原因,阿里云默认是最小的镜像,所以不必要的都剔除掉
保证最小可运行的环境!
解决方案:
将webapps.dist下的文件都拷贝到webapps下即可
root@645596565d3f:/usr/local/tomcat# ls 找到webapps.dist
BUILDING.txt LICENSE README.md RUNNING.txt conf logs temp webapps.dist
CONTRIBUTING.md NOTICE RELEASE-NOTES bin lib native-jni-lib webapps work
root@645596565d3f:/usr/local/tomcat# cd webapps.dist/ # 进入webapps.dist
root@645596565d3f:/usr/local/tomcat/webapps.dist# ls # 查看内容
ROOT docs examples host-manager manager
root@645596565d3f:/usr/local/tomcat/webapps.dist# cd …
root@645596565d3f:/usr/local/tomcat# cp -r webapps.dist/* webapps # 拷贝webapps.dist 内容给webapps
root@645596565d3f:/usr/local/tomcat# cd webapps #进入webapps
root@645596565d3f:/usr/local/tomcat/webapps# ls #查看拷贝结果
ROOT docs examples host-manager manager
安装成功
3.Docker部署Elasticsearch+kibana
(暂时不写)
4.Portainer可视化面板
什么是portainer?(Docker提供的一个图形化管理面板)
- portainer(先用这个)
#安装portainer
docker run -d -p 8080:9000 \ #做端口映射
–restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
- Rancher(CI/CD再用)
注册用户 username:admin
pssword:qaz1234567,然后登录
管理面板
1.镜像是什么?
镜像是一种轻量级、可执行的独立软件保,用来打包软件运行环境和基于运行环境开发的软件,他包含运行某个软件所需的所有内容,包括代码、运行时库、环境变量和配置文件。
所有应用,直接打包docker镜像,就可以直接跑起来!
如何得到镜像 ?
-
从远程仓库下载
-
别人拷贝给你
-
自己制作一个镜像 DockerFile
2.Docker镜像加载原理
UnionFs (联合文件系统)
UnionFs(联合文件系统):Union文件系统(UnionFs)是一种分层、轻量级并且高性能的文件系统,他支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下( unite several directories into a single virtual filesystem)。Union文件系统是 Docker镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。
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这里才200M?
答:对于个精简的OS,rootfs可以很小,只需要包合最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的Linux发行版, boots基本是一致的, rootfs会有差別,因此不同的发行版可以公用bootfs.
虚拟机是分钟级别,容器是秒级!
3.镜像分层原理
我们知道Docker的镜像是分层下载的
思考:为什么Docker镜像要采用这种分层的结构呢?
最大的好处,我觉得莫过于资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。
#查看镜像分层的方式可以通过:docker image inspect 镜像名
理解:
所有的 Docker镜像都起始于一个基础镜像层,当进行修改或培加新的内容时,就会在当前镜像层之上,创建新的镜像层。
举一个简单的例子,假如基于 Ubuntu Linux16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加 Python包,
就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创健第三个镜像层该像当前已经包含3个镜像层,如下图所示(这只是一个用于演示的很简单的例子)。
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点.
在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合,理解这一点非常重要。下图中举了一个简单的例子,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。
上图中的镜像层跟之前图中的略有区別,主要目的是便于展示文件
下图中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版。
文种情況下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件的更新版本作为一个新镜像层添加到镜像当中
Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统
Linux上可用的存储引撃有AUFS、 Overlay2、 Device Mapper、Btrfs以及ZFS。顾名思义,每种存储引擎都基于 Linux中对应的
件系统或者块设备技术,井且每种存储引擎都有其独有的性能特点。
Docker在 Windows上仅支持 windowsfilter 一种存储引擎,该引擎基于NTFS文件系统之上实现了分层和CoW [1]。
下图展示了与系统显示相同的三层镜像。所有镜像层堆并合井,对外提供统一的视图。
特点
Docker 镜像都是只读的,当容器启动时,一个新的可写层加载到镜像的顶部!
这一层就是我们通常说的容器层,容器之下的都叫镜像层!
4.Commit镜像
docker commit 提交容器成为一个新的副本
命令和git原理类似
docker commit -m=“描述信息” -a=“作者” 容器id 目标镜像名:[版本TAG]
实战测试
1、启动一个默认的tomcat
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker run -d -p 8080:8080 tomcat
de57d0ace5716d27d0e3a7341503d07ed4695ffc266aef78e0a855b270c4064e
2、发现这个默认的tomcat 是没有webapps应用,官方的镜像默认webapps下面是没有文件的!
#docker exec -it 容器id /bin/bash
[root@iz2zeak7sgj6i7hrb2g862z ~]# docker exec -it de57d0ace571 /bin/bash
root@de57d0ace571:/usr/local/tomcat#
3、从webapps.dist拷贝文件进去webapp
root@de57d0ace571:/usr/local/tomcat# cp -r webapps.dist/* webapps
root@de57d0ace571:/usr/local/tomcat# cd webapps
root@de57d0ace571:/usr/local/tomcat/webapps# ls
ROOT docs examples host-manager manager
4、将操作过的容器通过commit调教为一个镜像!我们以后就使用我们修改过的镜像即可,而不需要每次都重新拷贝webapps.dist下的文件到webapps了,这就是我们自己的一个修改的镜像。
docker commit -m=“描述信息” -a=“作者” 容器id 目标镜像名:[TAG]
docker commit -a=“kuangshen” -m=“add webapps app” 容器id tomcat02:1.0
[root@songqixiang /]# docker commit -a=“sqx” -m=“add webapps info” 0bf040b5e84d tomcat02:1.0
sha256:fd40769879b4a25a9798f02eea4a07ac14f6867139c34217f7717e1b01716df5
[root@songqixiang /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat02 1.0 fd40769879b4 7 minutes ago 673MB
tomcat latest 710ec5c56683 9 hours ago 668MB
nginx latest 08b152afcfae 2 weeks ago 133MB
portainer/portainer latest 580c0e4e98b0 4 months ago 79.1MB
centos latest 300e315adb2f 8 months ago 209MB
#测试启动自己的镜像
[root@songqixiang /]# docker run -d -it -p 8080:8080 --name tomcat03 tomcat02:1.0
6c5e1e9560c43674d404501786097c78c41cc340f2598592862f22f1bb7efc24
#启动成功!
[root@songqixiang /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6c5e1e9560c4 tomcat02:1.0 “catalina.sh run” 12 seconds ago Up 11 seconds 0.0.0.0:8080->8080/tcp tomcat03
总结:如果你想要保存当前容器的状态,就可以通过commit来提交,获得一个镜像,就好比我们我们使用虚拟机的快照。
学完上述即是入门!
============================================================================
1.什么是容器数据卷
将应用和环境打包成一个镜像!如果数据都在容器中,那么我们容器删除,数据就会丢失!需求:数据可以持久化,MySQL,容器删除了,删库跑路!需求:MySQL数据可以存储在本地!(持久化容器当中数据)
容器之间可以有一个数据共享的技术!Docker容器中产生的数据,同步到本地!
这就是卷技术!目录的挂载,将我们容器内的目录,挂载到Linux上面!
总结一句话:容器的持久化和同步操作!容器间也是可以数据共享的!
2.数据卷的使用:
方式一 :直接使用命令挂载 -v
-v, --volume list Bind mount a volume
docker run -it -v 主机目录:容器内目录 -p 主机端口:容器内端口
/home/ceshi:主机home目录下的ceshi文件夹 映射:centos容器中的/home
[root@iz2zeak7 home]# docker run -it -v /home/ceshi:/home centos /bin/bash
#这时候主机的/home/ceshi文件夹就和容器的/home文件夹关联了,二者可以实现文件或数据同步了
#通过 docker inspect 容器id 查看
[root@iz2zeak7sgj6i7hrb2g862z home]# docker inspect 6064c490c371
测试文件的同步:
再来测试!
1、停止容器
2、宿主机修改文件
3、启动容器
4、容器内的数据依旧是同步的
好处:我们以后修改只需要在本地修改即可,容器内会自动同步!
3.实战安装MySQL
思考:MySQL数据持久化的问题?
获取mysql镜像
[root@iz2zeak7sgj6i7hrb2g862z home]# docker pull mysql:5.7
运行容器,需要做数据挂载 #安装启动mysql,需要配置密码的,这是要注意点!
参考官网hub
docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
#启动我们得
-d 后台运行
-p 端口映射
-v 卷挂载
-e 环境配置
– name 容器名字
$ docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql03 mysql:5.7
启动成功之后,我们在本地使用sqlyog来测试一下
sqlyog-连接到服务器的3306–和容器内的3306映射
在本地测试创建一个数据库,查看一下我们映射的路径是否ok!
测试连接:注意3310端口要在阿里云服务器的安全组中打开,否则无法连接。
当我们在本地用SQLyog新建名称为test的数据库时候,容器容器也会创建
#挂载的卷目录,存在mysql数据,新加的test数据库也被同步!
[root@songqixiang /]# cd /home/mysql
[root@songqixiang mysql]# ls
conf data
[root@songqixiang mysql]# cd data/
[root@songqixiang data]# ls
auto.cnf client-cert.pem ibdata1 ibtmp1 private_key.pem server-key.pem
ca-key.pem client-key.pem ib_logfile0 mysql public_key.pem sys
ca.pem ib_buffer_pool ib_logfile1 performance_schema server-cert.pem test #test数据同步成功!
我们进行删除容器测试
#先stop停止容器,再删除容器!
[root@songqixiang /]# docker rm cfa3738a8146
cfa3738a8146
[root@songqixiang mysql]# cd /home/mysql
[root@songqixiang mysql]# ls
conf data
[root@songqixiang mysql]# cd data
[root@songqixiang data]# ls
auto.cnf client-cert.pem ibdata1 mysql public_key.pem sys
ca-key.pem client-key.pem ib_logfile0 performance_schema server-cert.pem test #test数据仍然存在
ca.pem ib_buffer_pool ib_logfile1 private_key.pem server-key.pem
结论:我们挂载到本地的数据卷依旧没有丢失,这就实现了容器数据持久化功能。
4.具名和匿名挂载
挂载方式二:匿名挂载
匿名挂载
-v 容器内路径!
$ docker run -d -P --name nginx01 -v /etc/nginx nginx
查看所有的volume(卷)的情况
$ docker volume ls
DRIVER VOLUME NAME # 容器内的卷名(匿名卷挂载)
local 21159a8518abd468728cdbe8594a75b204a10c26be6c36090cde1ee88965f0d0
local b17f52d38f528893dd5720899f555caf22b31bf50b0680e7c6d5431dbda2802c
这里发现,这种就是匿名挂载,我们在 -v只写了容器内的路径,没有写容器外的路径!
挂载方式三:具名挂载
具名挂载 -P:表示随机映射端口
$ docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
9663cfcb1e5a9a1548867481bfddab9fd7824a6dc4c778bf438a040fe891f0ee
查看所有的volume(卷)的情况
$ docker volume ls
DRIVER VOLUME NAME
local 21159a8518abd468728cdbe8594a75b204a10c26be6c36090cde1ee88965f0d0
local b17f52d38f528893dd5720899f555caf22b31bf50b0680e7c6d5431dbda2802c
local juming-nginx #多了一个名字
通过 -v 卷名:查看容器内路径
查看一下这个卷
$ docker volume inspect juming-nginx
[
{
“CreatedAt”: “2020-05-23T13:55:34+08:00”,
“Driver”: “local”,
“Labels”: null,
“Mountpoint”: “/var/lib/docker/volumes/juming-nginx/_data”, #默认目录
“Name”: “juming-nginx”,
“Options”: null,
“Scope”: “local”
}
]
所有的docker容器内的卷,没有指定目录的情况下都是在**/var/lib/docker/volumes/自定义的卷名/_data**下,
如果指定了目录,docker volume ls 是查看不到的。
5.区分三种挂载方式
三种挂载: 匿名挂载、具名挂载、指定路径挂载
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载 docker volume ls 是查看不到的
拓展:
通过 -v 容器内路径: ro rw 改变读写权限
ro #readonly 只读
rw #readwrite 可读可写
$ docer run -d -P --name nginx05 -v juming:/etc/nginx:ro nginx
$ docker run -d -P --name nginx05 -v juming:/etc/nginx:rw nginx
ro 只要看到ro就说明这个路径只能通过宿主机来操作,容器内部是无法操作!
6.初识Dockerfile
Dockerfile 就是用来构建docker镜像的构建文件!命令脚本!先体验一下!
通过这个脚本可以生成镜像,镜像是一层一层的,脚本是一个个的命令,每个命令都是一层!
创建一个dockerfile文件,名字可以随便 建议Dockerfile
文件中的内容: 指令(大写) + 参数
$ vim dockerfile1
FROM centos # 当前这个镜像是以centos为基础的
VOLUME [“volume01”,“volume02”] # 挂载卷的卷目录列表(多个目录)
CMD echo “-----end-----” # 输出一下用于测试
CMD /bin/bash # 默认走bash控制台
这里的每个命令,就是镜像的一层!
构建出这个镜像
-f dockerfile1 # f代表file,指这个当前文件的地址(这里是当前目录下的dockerfile1)
-t caoshipeng/centos # t就代表target,指目标目录(注意caoshipeng镜像名前不能加斜杠‘/’)
. # 表示生成在当前目录下
#通过dockerfile脚本构建自己的镜像
[root@songqixiang docker-test-volume]# docker build -f dockerfile1 -t sqx/centos .
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos
—> 300e315adb2f
Step 2/4 : VOLUME [“volume01”,“volume02”] #卷名列表
—> Running in dbd4cfe95d79
Removing intermediate container dbd4cfe95d79
—> 0b4a2cd8640e
Step 3/4 : CMD echo “----end----” #输出脚本命令
—> Running in 3833d6ca997f
Removing intermediate container 3833d6ca997f
—> 4222d1e017e6
Step 4/4 : CMD /bin/bash
—> Running in d1ec39c04193
Removing intermediate container d1ec39c04193
—> ae5796c1934e
Successfully built ae5796c1934e
Successfully tagged sqx/centos:latest
#查看自己构建的镜像!
[root@songqixiang docker-test-volume]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
sqx/centos latest ae5796c1934e 6 seconds ago 209MB
启动自己写的镜像
$ docker run -it f4a6b0d4d948 /bin/bash # 运行自己写的镜像
$ ls -l # 查看目录
这个卷和外部一定有一个同步的目录
查看卷挂载的情况
[root@6864b942c48b /]# [root@songqixiang docker-test-volume]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6864b942c48b ae5796c1934e “/bin/bash” 9 minutes ago Up 9 minutes awesome_chebyshev
容器id
[root@songqixiang docker-test-volume]# docker inspect 6864b942c48b 查看容器的详细信息
测试:在容器中的卷目录中新增文件,判断宿主机的挂载目录是否同步
(结果应该同步,但是没有同步!)
这种方式使用的十分多,因为我们通常会构建自己的镜像!
假设构建镜像时候没有挂载卷,要手动镜像挂载 -v 卷名:容器内路径!
7.Docker数据卷容器
多个MySQL同步数据!(容器间的数据同步)
命名的容器挂载数据卷!
测试 启动3个容器,通过刚才自己写的镜像启动
创建docker01:因为我本机是最新版,故这里用latest,狂神老师用的是1.0如下图
$ docker run -it --name docker01 caoshipeng/centos:latest
查看容器docekr01内容
$ ls
bin home lost+found opt run sys var
dev lib media proc sbin tmp volume01
etc lib64 mnt root srv usr volume02
不关闭该容器退出
CTRL + Q + P
创建docker02: 并且让docker02 继承 docker01
$ docker run -it --name docker02 --volumes-from docker01 caoshipeng/centos:latest
查看容器docker02内容
$ ls
bin home lost+found opt run sys var
dev lib media proc sbin tmp volume01
etc lib64 mnt root srv usr volume02
测试数据是否同步
再新建一个docker03同样继承docker01
$ docker run -it --name docker03 --volumes-from docker01 caoshipeng/centos:latest
$ cd volume01 #进入volume01 查看是否也同步docker01的数据
$ ls
docker01.txt
测试:可以删除docker01,查看一下docker02和docker03是否可以访问这个文件
测试发现:数据依旧保留在docker02和docker03中没有被删除
多个mysql实现数据共享
$ docker run -d -p 3306:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
$ docker run -d -p 3310:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7
这个时候,可以实现两个容器数据同步!
结论:
容器之间的配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。
但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的!
容器数据卷和数据卷容器的区别:
容器数据卷:就是当前容器的数据卷,目的是通过挂载持久化容器中的数据,本质:目录
数据卷容器:当多个容器的数据需要同步的时候,并且当前容器是父容器,其余的所有容器都挂在于这个父容器 本质:容器
1.DockerFile介绍
dockerfile
是用来构建docker镜像的文件!命令参数脚本!
构建步骤:
1、 编写一个dockerfile文件
2、 docker build 构建称为一个镜像
3、 docker run运行镜像
4、 docker push发布镜像(DockerHub 、阿里云仓库)
去Dockerhub可以发现,每个镜像其本质就是一个dockerfile
点击后跳到一个Dockerfile
很多官方镜像都是基础包,很多功能没有,我们通常会自己搭建自己的镜像!
官方既然可以制作镜像,那我们也可以!
2.DockerFile构建过程
基础知识:
1、每个保留关键字(指令)都是必须是大写字母
2、执行从上到下顺序
3、#表示注释
4、每一个指令都会创建提交一个新的镜像,并提交!
Dockerfile是面向开发的,我们以后要发布项目,做镜像,就需要编写dockerfile文件,这个文件十分简单!
Docker镜像逐渐成企业交付的标准,必须要掌握!
-
DockerFile:构建文件,定义了一切的步骤,源代码
-
DockerImages:通过DockerFile构建生成的镜像,最终发布和运行产品。
-
Docker容器:容器就是镜像运行起来提供服务。
3.DockerFile指令
FROM # from:基础镜像,一切从这里开始构建
MAINTAINER # maintainer:镜像是谁写的, 姓名+邮箱
RUN # run:镜像构建的时候需要运行的命令
ADD # add:步骤,tomcat镜像,这个tomcat压缩包!添加内容 添加同目录
WORKDIR # workdir:镜像的工作目录
VOLUME # volume:挂载的目录
EXPOSE # expose:保留端口配置
CMD # cmd:指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT # entrypoint:指定这个容器启动的时候要运行的命令,可以追加命令
ONBUILD # onbuild:当构建一个被继承DockerFile这个时候就会运行onbuild的指令,触发指令
COPY # copy:类似ADD,将我们文件拷贝到镜像中
ENV # env:构建的时候设置环境变量!
通俗介绍:
4.创建自己的镜像
前提:scratch镜像
[Docker Hub 中 99%的镜像都是从这个基础镜像过来的 FROM scratch,然后配置需要的软件和配置来进行构建。]
FROM scratch
ADD centos-7-x86_64-docker.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=“20200504” \
org.opencontainers.image.title=“CentOS Base Image” \
org.opencontainers.image.vendor=“CentOS” \
org.opencontainers.image.licenses=“GPL-2.0-only” \
org.opencontainers.image.created=“2020-05-04 00:00:00+01:00”
CMD [“/bin/bash”]
创建自己的Centos
1./home下新建dockerfile目录
$ mkdir dockerfile
2. dockerfile目录下新建mydockerfile-centos文件
$ vim mydockerfile-centos
3.编写Dockerfile配置文件
FROM centos # 基础镜像是官方原生的centos
MAINTAINER cao1165680007@qq.com # 作者
ENV MYPATH /usr/local # 配置环境变量的目录
WORKDIR $MYPATH # 将工作目录设置为 MYPATH
RUN yum -y install vim # 给官方原生的centos 增加 vim指令
RUN yum -y install net-tools # 给官方原生的centos 增加 ifconfig命令
EXPOSE 80 # 暴露端口号为80
CMD echo $MYPATH # 输出下 MYPATH 路径 echo作用类似于printf,控制台打印
CMD echo “-----end----”
CMD /bin/bash # 启动后进入 /bin/bash
4.通过这个文件构建镜像
命令: docker build -f 文件路径 -t 镜像名:[tag] .
$ docker build -f mydockerfile-centos -t mycentos:0.1 .
5.出现下图后则构建成功
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mycentos 0.1 cbf5110a646d 2 minutes ago 311MB
6.测试运行
$ docker run -it mycentos:0.1 # 注意带上版本号,否则每次都回去找最新版latest
$ pwd
/usr/local # 与Dockerfile文件中 WORKDIR 设置的 MYPATH 一致
$ vim # vim 指令可以使用
$ ifconfig # ifconfig 指令可以使用
docker history 镜像id 查看镜像构建历史步骤
$ docker history 镜像id
对上述指令测试:
我们可以列出本地进行的变更历史
我们平时拿到一个镜像,可以用 “docker history 镜像id” 研究一下是什么做的
5.CMD 和 ENTRYPOINT区别
#概述
CMD # 指定这个容器启动的时候要运行的命令,只有最后一个会生效,可被替代。
ENTRYPOINT # 指定这个容器启动的时候要运行的命令,可以追加命令
测试CMD指令
编写dockerfile文件
$ vim dockerfile-test-cmd
FROM centos
CMD [“ls”,“-a”] # 启动后执行 ls -a 命令
构建镜像
$ docker build -f dockerfile-test-cmd -t cmd-test:0.1 .
运行镜像
$ docker run cmd-test:0.1 # 由结果可得,运行后就执行了 ls -a 命令
.
…
.dockerenv
bin
dev
etc
home
想追加一个命令 -l 成为ls -al:展示列表详细数据
$ docker run cmd-test:0.1 -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: “-l”:
executable file not found in $PATH": unknown.
ERRO[0000] error waiting for container: context canceled
cmd的情况下 -l 替换了CMD[“ls”,“-l”] 而 -l 不是命令所以报错
测试ENTRYPOINT指令
编写dockerfile文件
$ vim dockerfile-test-entrypoint
FROM centos
ENTRYPOINT [“ls”,“-a”]
构建镜像
$ docker build -f dockerfile-test-entrypoint -t cmd-test:0.1 .
运行镜像
$ docker run entrypoint-test:0.1
.
…
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found …
我们的命令,是直接拼接在我们得ENTRYPOINT命令后面的
$ docker run entrypoint-test:0.1 -l
total 56
drwxr-xr-x 1 root root 4096 May 16 06:32 .
drwxr-xr-x 1 root root 4096 May 16 06:32 …
-rwxr-xr-x 1 root root 0 May 16 06:32 .dockerenv
lrwxrwxrwx 1 root root 7 May 11 2019 bin -> usr/bin
drwxr-xr-x 5 root root 340 May 16 06:32 dev
drwxr-xr-x 1 root root 4096 May 16 06:32 etc
drwxr-xr-x 2 root root 4096 May 11 2019 home
lrwxrwxrwx 1 root root 7 May 11 2019 lib -> usr/lib
lrwxrwxrwx 1 root root 9 May 11 2019 lib64 -> usr/lib64 …
Dockerfile中很多命令都十分的相似,我们需要了解它们的区别,我们最好的学习就是对比他们然后测试效果!
总结:CMD是覆盖,ENTRYPOINT是追加
6.实战:Tomcat镜像
1.准备tomcat和jdk的Linux下压缩包
然后,使用Xftp上传到服务器
2.进入我们放置压缩包目录,并创建Readme文件
3.创建Dockerfile文件
[root@songqixiang sqx]# vim Dockerfile #编写Dockerfile【官方推荐用名】
[root@songqixiang sqx]# cat Dockerfile
FROM centos #基础镜像
MAINTAINER sqx481072783@qq.com #作者信息
COPY readme.txt /usr/local/readme.txt #复制readme.txt文件
ADD jdk-8u161-linux-x64.tar.gz /usr/local/ #添加JDK (ADD命令会自动解压)
ADD apache-tomcat-9.0.46.tar.gz /usr/local/ #添加Tomcat
RUN yum -y install vim #安装Vim,默认情况基础Centos比较简单没有Vim
ENV MYPATH /usr/local #配置环境变量
WORKDIR $MYPATH #设置工作目录
ENV JAVA_HOME /usr/local/jdk1.8.0_161 #在容器中,配置java环境
ENV CLASSPATH J A V A H O M E / l i b / d t . j a r : JAVA_HOME/lib/dt.jar: JAVAHOME/lib/dt.jar:JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.46 #在容器中,配置Tomcat环境
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.46
ENV PATH P A T H : PATH: PATH:JAVA_HOME/bin: C A T A L I N A H O M E / l i b : CATALINA_HOME/lib: CATALINAHOME/lib:CATALINA_HOME/bin
EXPOSE 8080 #容器暴露8080端口
CMD /usr/local/apache-tomcat-9.0.46/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.46/logs/catalina.out #启动Tomcat的命令,以及Tomcat的日志作用!
4.构建镜像
[root@songqixiang sqx]# docker build -t diytomcat . #不加-f的原因是,我们采用的官方命名,可以自己找到文件!
#分层构建后,构建成功的标识
Successfully built b15ec599e705
Successfully tagged diytomcat:latest
5.run镜像后台运行(启动容器)·
#启动容器(并进行挂载,将tomcat下的webapps目录挂载到宿主机,这样我们可以在宿主机发布项目!,test看作一个项目!)
[root@songqixiang sqx]# docker run -d -p 8080:8080 --name mytomcat -v /home/sqx/test:/usr/local/apache-tomcat-9.0.46/webapps/test -v /home/sqx/tomcatlogs:/usr/local/apache-tomcat-9.0.46/logs diytomcat
34c635b3be8f93c361066407fcd11493ad34b8684cfac2f0e00b736989db0726
#查看当前运行容器,启动成功!
[root@songqixiang sqx]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
34c635b3be8f diytomcat “/bin/sh -c '/usr/lo…” 5 seconds ago Up 4 seconds 0.0.0.0:8080->8080/tcp mytomcat
#进入容器
[root@songqixiang sqx]# docker exec -it 34c635b3be8f /bin/bash
[root@34c635b3be8f local]# ls
aegis apache-tomcat-9.0.46 bin etc games include jdk1.8.0_161 lib lib64 libexec readme.txt sbin share src
[root@34c635b3be8f local]# ls -ll #查看容器环境目录,可以看到jdk和tomcat
total 56
drwxr-xr-x 3 root root 4096 Aug 18 08:01 aegis
drwxr-xr-x 1 root root 4096 Aug 18 07:49 apache-tomcat-9.0.46
drwxr-xr-x 2 root root 4096 Nov 3 2020 bin
drwxr-xr-x 2 root root 4096 Nov 3 2020 etc
drwxr-xr-x 2 root root 4096 Nov 3 2020 games
drwxr-xr-x 2 root root 4096 Nov 3 2020 include
drwxr-xr-x 8 10 143 4096 Dec 20 2017 jdk1.8.0_161
drwxr-xr-x 2 root root 4096 Nov 3 2020 lib
drwxr-xr-x 3 root root 4096 Dec 4 2020 lib64
drwxr-xr-x 2 root root 4096 Nov 3 2020 libexec
-rw-r–r-- 1 root root 0 Aug 18 02:52 readme.txt
drwxr-xr-x 2 root root 4096 Nov 3 2020 sbin
drwxr-xr-x 5 root root 4096 Dec 4 2020 share
drwxr-xr-x 2 root root 4096 Nov 3 2020 src
6.访问测试
模拟一个项目发布的过程
一个简单的项目,需要web.xml和index.jsp,我们将其放在test目录下,这样test就够成一个简单的web项目!
测试:我们只需访问/test 默认会返回index.jsp文件!
[root@songqixiang WEB-INF]# vim web.xml #将下面的代码拷贝即可
[root@songqixiang WEB-INF]# cd …
[root@songqixiang test]# ls #将test模拟称为一个web项目!
WEB-INF
[root@songqixiang test]# vim index.jsp
<?xml version="1.0" encoding="UTF-8"?>web.xml
<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”>
index.jsp
<%@ page contentType=“text/html;charset=UTF-8” language=“java” %>
Hello World!
<%Styetem.out.println(“-----hello , Docker----------”)%>
项目部署成功!
发现:项目部署成功,可以直接访问!(由于做了卷挂载,我们直接在本地编写项目就可以发布了!)
我们以后开发的步骤:需要掌握Dockerfile的编写!我们之后的一切都是使用docker镜像来发布运行!
7.发布镜像到Dockerhub
1、先取Dockerhub注册账号 :地址 https://hub.docker.com/
2、登录Dockerhub
3.在服务器中登录Dockerhub
[root@songqixiang sqx]# docker login -u songqixiang
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
4.提交镜像
#发布镜像
[root@songqixiang sqx]# docker push diytomcat
Using default tag: latest
The push refers to repository [docker.io/library/diytomcat]
ddbc96880ae9: Preparing
4425b5e67f5c: Preparing
28b9491b6232: Preparing
97a9160dc10c: Preparing
2653d992f4ef: Preparing
denied: requested access to the resource is denied #发布失败 会发现push不上去,因为如果没有前缀的话默认是push到 官方的library
#解决:发布镜像的发布的镜像需要 dockerhub的用户名/镜像名:版本号的格式
[root@songqixiang sqx]# docker tag b15ec599e705 songqixiang/tomcat:1.0 #docker tag 更改名字
#方法二:build的时候添加你的dockerhub用户名,然后在push就可以放到自己的仓库了 docker build -t kuangshen/mytomcat:0.1 .
[root@songqixiang sqx]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
diytomcat latest b15ec599e705 2 hours ago 678MB
songqixiang/tomcat 1.0 b15ec599e705 2 hours ago 678MB #产生新的镜像!
#重新发布,发布成功!
[root@songqixiang sqx]# docker push songqixiang/tomcat:1.0
The push refers to repository [docker.io/songqixiang/tomcat]
ddbc96880ae9: Pushing [===> ] 4.937MB/68.07MB
4425b5e67f5c: Pushing [===> ] 1.024MB/15.92MB
28b9491b6232: Pushing [> ] 2.16MB/384.5MB
97a9160dc10c: Pushing 2.56kB
2653d992f4ef: Pushing [> ] 3.25MB/209.3MB
发布成功!
8.发布到阿里云镜像服务
bilibili视频讲解:https://www.bilibili.com/video/BV1og4y1q7M4?p=32
看aliyun官网 很详细https://cr.console.aliyun.com/repository/
$ sudo docker login --username=zchengx registry.cn-shenzhen.aliyuncs.com
$ sudo docker tag [ImageId] registry.cn-shenzhen.aliyuncs.com/dsadxzc/cheng:[镜像版本号]
修改id 和 版本
sudo docker tag a5ef1f32aaae registry.cn-shenzhen.aliyuncs.com/dsadxzc/cheng:1.0
修改版本
$ sudo docker push registry.cn-shenzhen.aliyuncs.com/dsadxzc/cheng:[镜像版本号]
9.Docker流程小结
准备工作:清空容器和镜像
删除全部容器
$ docker rm -f $(docker ps -aq)
删除全部镜像
$ docker rmi -f $(docker images -aq)
测试
思考:Docker 是如果处理容器网络访问的?
容器1中的tomcat如何访问容器2中的MySQL?
[root@songqixiang ~]# docker run -d -P --name tomcat01 tomcat #后台运行容器
[root@songqixiang ~]# docker exec -it tomcat01 ip addr #不进入容器查看容器ip
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo #本机环回
valid_lft forever preferred_lft forever
62: eth0@if63: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever #docker分配给容器的
[root@songqixiang ~]# ping 172.17.0.2 #宿主机ping容器
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.109 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.080 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.083 ms
64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.087 ms #成功!
#思考: #linux能不能ping通容器内部? 可以
#容器内部可以ping通外界吗? 可以!
#原因: #因为容器的ip:172.17.0.2 宿主机的ip:127.0.0.1 ,他们属于同一个网段,类似路由器
#容器时宿主机产生的,宿主机当然能ping通容器!
理解Docker0
原理:
我们每启动一个docker容器,docker就会给docker容器分配一个ip,我们只要按照了docker,就会有一个docker0桥接模式,使用的技术是veth-pair技术、参考文章:https://www.cnblogs.com/bakari/p/10613710.html
再次测试 ip addr
我们发现这个容器带来网卡,都是一对对的
veth-pair 就是一对的虚拟设备接口,他们都是成对出现的,一端连着协议,一端彼此相连
正因为有这个特性 veth-pair 充当一个桥梁,连接各种虚拟网络设备的
OpenStac,Docker容器之间的连接,OVS的连接,都是使用evth-pair技术
3、我们来测试下tomcat01和tomcat02是否可以ping通
获取tomcat01的ip 172.17.0.2
$ docker-tomcat docker exec -it tomcat01 ip addr
550: eth0@if551: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
让tomcat02 ping tomcat01
$ docker-tomcat docker exec -it tomcat02 ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.098 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.071 ms
结论:容器和容器之间是可以互相ping通
网络模型图
结论:tomcat01和tomcat02公用一个路由器,docker0。
所有的容器不指定网络的情况下,都是docker0路由的,docker会给我们的容器分配一个默认的可用ip。
小节
Docker使用的是Linux的桥接,宿主机是一个Docker容器的网桥 docker0
Docker中所有网络接口都是虚拟的,虚拟的转发效率高(内网传递文件)
只要容器删除,对应的网桥一对就没了!
–link
思考一个场景:我们编写了一个微服务,database url=ip: 项目不重启,数据ip换了,我们希望可以处理这个问题,可以通过名字来进行访问容器?
$ docker exec -it tomcat02 ping tomca01 # ping不通
ping: tomca01: Name or service not known
运行一个tomcat03 --link tomcat02
$ docker run -d -P --name tomcat03 --link tomcat02 tomcat #容器tomcat03连接容器tomcat02
5f9331566980a9e92bc54681caaac14e9fc993f14ad13d98534026c08c0a9aef
3连接2
用tomcat03 ping tomcat02 可以ping通(正向ping)
$ docker exec -it tomcat03 ping tomcat02
PING tomcat02 (172.17.0.3) 56(84) bytes of data.
64 bytes from tomcat02 (172.17.0.3): icmp_seq=1 ttl=64 time=0.115 ms
64 bytes from tomcat02 (172.17.0.3): icmp_seq=2 ttl=64 time=0.080 ms
用tomcat02 ping tomcat03 ping不通(反向ping)
探究
docker network --help
[root@songqixiang ~]# docker network ls #查看当前网络情况
NETWORK ID NAME DRIVER SCOPE
778ed0cf2e01 bridge bridge local
c531491ac359 host host local
402e100529f7 none null local
[root@songqixiang ~]#docker network inspect 网络id #网段相同,查看某个网络的详细情况!
[root@songqixiang ~]#docker inspect tomcat03 #查看tomcat03的详细信息
查看tomcat03里面的/etc/hosts发现有tomcat02的配置
–-link 本质就是在hosts配置中添加映射
但是,现在使用Docker已经不建议使用–link了!
我们采取,自定义网络,但是【自定义网络不适用docker0】docker0问题:不支持容器名连接访问