Docker

1. Docker安装

1.1 Docker的基本组成

镜像(image):

docker镜像就好比是一个模板,可以通过这个模板来创建容器服务,tomcat镜像------>run------->tomcat01容器(提供服务器),通过这个镜像可以创建多个容器(最终服务运行或者项目运行就是在容器中的)

容器(container):

Docker利用容器技术,独立运行一个或者一组应用,通过镜像来创建的

启动,停止,删除,基本命令

目前可以把容器理解为一个简易的Linux系统

仓库(repository):

仓库就是存放镜像的地方

仓库分为公有仓库和私有仓库

Docker Hub

阿里云等等都有容器服务器(默认在国外,配置镜像加速)

1.2 安装Dokcer

环境准备

  1. 需要linux基础
  2. Centos7
  3. 使用软件进行远程连接

环境查看

# 系统内核是3.10以上的
unmae -r
# 系统版本
cat /etc/os-release

安装

帮助文档

# 1.卸载旧的版本
yum remove docker 
                  docker-client 
                  docker-client-latest 
                  docker-common 
                  docker-latest 
                  docker-latest-logrotate 
                  docker-logrotate 
                  docker-engine
                  
# 2.需要的安装包
yum install -y yum-utils

# 3.设置镜像的仓库
yum-config-manager 
    --add-repo 
    https://download.docker.com/linux/centos/docker-ce.repo  # 默认是国外的,需要换成国内的
    
yum-config-manager 
    --add-repo 
    https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    
# 更新yum软件包索引
yum makecache fast

# 4. 安装docker相关的   docker-ce 社区版 ee企业版
yum install docker-ce docker-ce-cli containerd.io

# 5.启动docker
systemctl start docker

# 6.使用docker version测试是否安装成功
docker version

# 7.hello-word
docker run hello-word

# 8.查看下载的这个hello-word镜像
docker images

1.3 卸载docker

# 1.卸载依赖
yum remove docker-ce docker-ce-cli containerd.io

# 2.删除资源
rm -rf /var/lib/docker

# /var/lib/docker docker的默认工作路径

1.4 阿里云镜像加速

  1. 登录阿里云找到容器服务

  2. 找到镜像加速的地址

  3. 配置应用

    mkdir -p /etc/docker
    # 编辑daemon.json
    tee /etc/docker/daemon.json <<-'EOF'
    # 设置加速器地址
    {
      "registry-mirrors": ["https://xxxxxxxx.mirror.aliyuncs.com"]
    }
    EOF
    # 最后重新加载和重启docker:
    systemctl daemon-reload
    
    systemctl restart docker
    
    mkdir -p /etc/docker
    tee /etc/docker/daemon.json <<-'EOF'
    {
      "registry-mirrors": ["https://me0kxh75.mirror.aliyuncs.com"]
    }
    EOF
    systemctl daemon-reload
    systemctl restart docker
    

1.5 run流程

1.6 底层原理

docker是怎么工作的?

Docker 是一个client-server 结构的系统,Docker的守护进程运行在主机上,通告Socker从客户端访问

Dokcer server 接收到Docker-client 的指令,就会执行这个命令

Docker为什么比虚拟机快

  • Docker有着比虚拟机更少的抽象层
  • Docker 利用的是宿主机的内核,VM需要Guest OS
  • 所以,新建一个容器的时候,Docker不需要虚拟机一样重新加载一个操作系统的内核,避免引导。虚拟机是加载Guest OS,分钟级别的,而docker是利用宿主机的操作系统,省略了这个复杂的过程,秒级

2. Docker常用命令

2.1 帮助命令

docker version    # 显示docker的版本信息
docker info       # 显示docker的系统信息,包括镜像和容器的数量
docker 命令 --help   #万能命令

2.2 镜像命令

2.2.1 docker images查看所有本地的主机上的镜像

docker images

# 解释
REPOSITORY  镜像的仓库源
TAG			镜像的标签
IMAGE ID	镜像的ID
CREATED		镜像的创建时间
SIZE		镜像的大小

# 可选项
-a  # 列出所有的镜像
-q  # 只显示镜像的ID

2.2.2 docker search 搜索镜像

docker search mysql

# 可选项
--filter=STARS=3000   #搜索出来的镜像是STARS大于3000的

2.2.3 docker pull 下载镜像

# 下载镜像
docker pull 镜像名[:tag]

如果不写tag,默认就是latest
分层下载,docker image的核心,联合文件系统
Digest #签名
docker.io/library/mysql:latest  #真实地址

#等价于他
docker pull mysql
docker pull docker.io/library/mysql:latest

# 指定版本下载
docker pull mysql:5.7

2.2.4 docker rmi 删除镜像

docket rmi -f 镜像id  #删除指定镜像
docket rmi -f 镜像id 镜像id  #删除多个镜像
docket rmi -f $(docker images -aq)  #递归删除所有镜像

2.3 容器命令

说明:我们有了镜像才可以创建容器,Linux,下载一个centos 镜像来测试学习

docker pull centos

2.3.1 新建容器并启动 run

docker run [可选参数] image

# 参数说明
--name="Name"   # 容器名字  tomcat01 tomcat02,用来区分容器
-d				# 后台方式运行
-it 				# 使用交互方式运行,进入容器查看内容
-p				# 指定容器的端口 -p 8080:8080
	-p ip:主机端口:容器端口
	-p 主机端口:容器端口(常用)
	-p 容器端口
	容器端口
-p				# 随机指定端口

# 测试
docker run -it centos /bin/bash  # 启动并进入容器
	exit # 从容器中退回到主机

2.3.2 docker ps 列出所有运行的容器

docker ps  # 列出当前正在运行的容器

-a  # 列出当前正在运行的容器+历史运行过的容器
-n=?  # 显示最近创建的容器,例如-n=1,显示最近创建的一个容器
-q  # 只显示容器的编号

2.3.3 退出容器

exit   # 直接容器停止并退出
ctrl+p+q  #容器不停止退出

2.3.4 删除容器 rm

docker rm 容器id   		#删除指定的容器,不能删除正在运行的容器,如果想要强制删除 rm -f
docker rm -f $(docker ps -aq)  #删除所有的容器
docker ps -a -q|xargs docker rm #删除所有的容器

2.3.5 启动和停止容器的操作

docker start 容器id         # 启动容器
docker restart 容器id		  # 重启容器
docker stop 容器id		  # 停止当前正在运行的容器
docker kill 容器id		  # 强制停止当前容器

2.4 常用其他命令

2.4.1 后台启动容器

# 命令 docker run -d 镜像名
docker run -d centos

# 问题 docker ps 发现centos停止了

# 常见的坑,docker 容器使用后台运行,就必须要有一个前台进程,docker发现没有应用,就会自动停止
# nginx,容器启动后,发现自己没有提供服务,就会立刻停止,就是没有程序了

2.4.2 查看日志

docker logs 
# 显示日志
-tf   #显示全部日志
--tail number #显示指定数量的日志

docker logs -f -t --tail 容器id   # 没有日志

#自己编写一段shell脚本
docker run -d centos /bin/bash -c "while true;do echo zjc;sleep 1;done"

docker logs -tf --tail 10 容器id   

2.4.3 查看容器中进程信息 ps

# 命令 docker top容器id

2.4.4 查看镜像的元数据 inspect

docker inspect 容器id

2.4.5 进入当前正在运行的容器 exec attach

# 我们通常容器都是使用后台方式运行的,需要进入容器,修改一些配置

#命令
# 方式一
docker exec -it 容器id /bin/bash

# 方式二xi
docker attach 容器id

#区别
docker exec #进入容器之后开启一个新的终端,可以在里面操作(常用)
docker attach # 进入容器正在执行的终端,不会启动新的进程

2.4.6 从容器内拷贝文件到主机上

docker cp 容器id:容器内路径 目的地主机路径
#拷贝是一个手动过程,可以使用-v卷的技术,可以实现

2.5 常用命令小结

attach					# 当前shell下attach连接指定运行镜像
build					# 通过dockerfile定制镜像
commit					# 提交当前容器为新的镜像
cp					# 从容器中拷贝指定文件或者目录到宿主机中
create					# 创建一个新的容器,同run 但不启动容器
diff					# 查看docker 容器变化
events					# 从docker 服务获取容器实时事件
exec					# 在已存在的容器上运行命令
export					# 导出容器的内容作为一个 tar 归档文件[对应import]
history					# 展示一个镜像形成历史
images					# 列出系统当前镜像
import        			        # 从tar包中的内容创建一个新的文件系统映像[对应export]
info					# 显示系统相关信息
inspect					# 查看容器详细信息
kill					# kill 指定容器
load					# 从一个tar 包中加载一个镜像[对应save]
login 					# 注册或者登陆一个docker源服务器
logout					# 从当前docker registry退出
logs					# 输出当前容器日志信息
port					# 查看映射端口对应的容器内部源端口
pause     				# 暂停容器
ps					# 列出容器列表
pull					# 从docker镜像源服务器拉取指定镜像或者库镜像
push					# 推送指定镜像或者库镜像至docker源服务器
restart					# 重启运行的容器
rm					# 移除一个或者多个容器
rmi					# 移除一个或多个镜像[无容器使用该镜像才可删除,否则需要删除相关容器才可继续或 -f 强制删除]
run 					# 创建一个新的容器并运行一个命令
save					# 保存一个镜像为一个tar包[对应load]
search					# 在docker hub 中搜索镜像
start 					# 启动容器
stop					# 停止容器
tag					# 给源中镜像打标签
top					# 查看容器中运行的进程信息
unpause					# 取消暂停容器
version					# 查看docker版本号
wait					# 截取容器停止时的退出状态值

3. 作业练习

3.1 部署Nginx

# 1.搜索镜像 search,可以去docker 搜索,可以看到帮助文档
# 2.下载镜像 pull
# 3.运行测试
docker images 

# -d 后台运行
# --name 给容器命名
# -p 宿主机端口,容器内部端口
docker run -d --name nginx01 -p 3344:80 nginx
docker ps
curl localhost:3344

# 进入容器
docker exec -it nginx01 /bin/bash

docker stop 容器id


# 思考问题:我们每次改动nginx配置文件,都需要进入容器内部,十分麻烦,我们可以在容器外部提供一个映射路径,到达在容器外部修改文件,容器内部就可以自动修改   -v 数据卷技术

端口暴露的概念

3.2 docker来装一个tomcat

# 官方的使用
docker run -it --rm tomcat:9.0   # 用完就删除

# 我们之前的启动都是后台,停止容器之后,容器还是可以查看到,docker run -it --rm tomcat:9.0

# 下载再启动
docker pull tomcat

# 启动运行
docker run -d -p 3355:8080 --name tomcat101 tomcat

# 测试访问没有问题

# 进入容器
docker exec -it tomcat101 /bin/bash

# 发现问题:1. linux命令少了  2. 没有webapps
# 阿里云镜像的原因,默认是最小的镜像,所有不必要的都删除掉,保证最小可运行的环境
  
思考:在容器外部提供给一个映射路径,webapps,我们在外部防止项目,就自动同步到内部就好了

3.3 部署es+kibana

# es 暴漏的端口很多
# es 十分的耗内存
# es 的数据一般需要放置到安全目录
# --net somenetwork? 网络配置

# 启动es
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2

# 启动了linux 就卡住了,docker stats 查看CPU的状态
# es 十分消耗内存

# 修改配置文件 -e环境配置修改
docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e ES_JAVA_OPTS="Xms64m -Xmx512m" elasticsearch:7.6.2

curl localhost:9200

使用kibana连接es,思考网络如何才能连接过去

4.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再用)

什么是portainer?

  • Docker图形化界面管理工具,提供一个后台面板供我们操作
docker run -d -p 8080:9000 
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

访问测试:http://ip:8080

5. Docker镜像讲解

5.1 镜像是什么

镜像是一种轻量级、可执行的独立软件保,用来打包软件运行环境和基于运行环境开发的软件,他包含运行某个软

件所需的所有内容,包括代码、运行时库、环境变量和配置文件

所有的应用,直接打包docker镜像,就可以直接跑起来

5.1.1如何得到镜像:

  • 远程仓库下载
  • 其他人拷贝给你
  • 自己制作一个镜像dockerfile

5.2 docker镜像加载原理

5.2.1 UnionFS(联合文件系统)

UnionFs(联合文件系统):Union文件系统(UnionFs)是一种分层、轻量级并且高性能的文件系统,他支持对

文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下( unite

several directories into a single virtual filesystem)。Union文件系统是 Docker镜像的基础。镜像可以通过分层

来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像

特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起

来,这样最终的文件系统会包含所有底层的文件和目录

5.2.2 docker镜像加载原理

docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。

boots(boot file system

主要包含 bootloader和 Kernel, bootloader主要是引导加 kernel, Linux刚启动时会加bootfs文件系统,在 Docker镜像的最底层是 boots。

这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。

当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由 bootfs转交给内核,此时系统也会卸载bootfs。

rootfs(root file system) 在 bootfs之上。

包含的就是典型 Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。

rootfs就是各种不同的操作系统发行版,比如 Ubuntu, Centos等等。

对于个精简的OS,rootfs可以很小,只需要包合最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就可以了

由此可见对于不同的Linux发行版, boots基本是一致的, rootfs会有差別,因此不同的发行版可以公用bootfs.

虚拟机是分钟级别,容器是秒级!

5.2.3 分层理解

为什么要采用分层结构?

最大的好处,我觉得莫过于资源共享了!比如有多个镜像都从相同的Base镜像构建而来,那么宿主机只需在磁盘上保留一份base镜像,同时内存中也只需要加载一份base镜像,这样就可以为所有的容器服务了,而且镜像的每一层都可以被共享。

所有的 Docker镜像都起始于一个基础镜像层,当进行修改或培加新的内容时,就会在当前镜像层之上,创建新的镜像层。

查看镜像分层的方式

docker image inspect

特点

5.2.4 commit镜像

docker commit  提交容器成为一个新的副本

# 命令
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[TAG]

实战测试

# 启动一个默认的tomcat

# 发现这个默认的tomcat是没有webapps应用,镜像的原因,官方的镜像默认 webapps下面是没有文件的

# 手动拷贝进去了基本的文件

# 将修改后的容器通过commit提交为一个新的镜像,我们以后就可以使用修改过的镜像,这就是自己修改过的一个镜像

如果想要保存当前容器的状态,我们可以通过commit来提交,获得一个镜像,类似于虚拟机的快照

6. 容器数据卷

6.1 什么是容器数据卷

docker的理念回顾

将应用和环境打包成一个镜像

如果数据都在容器中,那么删除容器,数据就会丢失! 需求:数据可以持久化

MySQL,容器删了,删库跑路!需求:MySQL数据可以存储在本地

容器之间可以有一个数据共享的技术!Docker容器中产生的数据,同步到本地!

这就是卷技术!!目录的挂载,将我们容器内的目录,挂载到Linux上面

6.1.1 总结:

**容器的持久化和同步操作!容器之间也是可以数据共享的** 

6.1.2 使用数据卷

方式一:直接使用命令来挂载 -v

docker run -it -v  主机目录:容器内目录

# 测试
docker run -it -v /home/ceshi:/home centos /bin/bash 

# 启动起来之后,我们可以通过 docker inspect 容器id 来查看元数据

# 再次测试
1. 停止容器
2. 在宿主机上修改文件
3. 再次启动容器
4. 容器内的数据依旧是同步的

好处:

我们以后修改只需要在本地修改即可,容器内自动同步!

6.2 实战:安装MySQL

6.2.1 思考:MySQL 数据持久化问题

# 获取镜像
docker pull mysql:5.7

# 运行容器,数据挂载   # 安装启动mysql,需要配置密码!!!
# 官方测试:docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag

# 运行容器,数据挂载   # 安装启动mysql,需要配置密码!!!
-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 mysql01 mysql:5.7

# 启动成功之后,我们在本地使用sql yog测试连接
# sqlyog 连接到服务器的3310 --- 3310和容器内的3306映射,这个时候就可以连接上了

# 在本地测试创建一个数据库,查看一下我们映射的路径是否OK

6.2.2 假设我们将容器删除

发现,我们挂载到本地的数据卷依旧没有丢失,这就实现了容器数据持久化功能

6.3 具名和匿名挂载

# 匿名挂载
-v 容器内路径
docker run -d -P --name nginx01 -v /etc/nginx nginx
# 查看所有的volume的情况
➜  ~ docker volume ls    
DRIVER              VOLUME NAME
local               33ae588fae6d34f511a769948f0d3d123c9d45c442ac7728cb85599c2657e50d        
# 这里发现,这种就是匿名挂载,我们在 -v只写了容器内的路径,没有写容器外的路径!

# 具名挂载
➜  ~ docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx nginx
➜  ~ docker volume ls                  
DRIVER              VOLUME NAME
local               juming-nginx

# 通过 -v 卷名:容器内路径

# 查看一下这个卷
docker volume inspect juming-nginx

# 所有的docker容器内的卷,没有指定目录的情况下都是在/var/lib/docker/volumes/xxxx/_data,如果指定了目录,docker volume ls 是查看不到的

我们通过具名挂载可以方便的找到我们的一个卷,大多数情况在使用的是具名挂载

# 三种挂载: 匿名挂载、具名挂载、指定路径挂载
-v 容器内路径			#匿名挂载
-v 卷名:容器内路径		#具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载 docker volume ls 是查看不到的

6.3.1拓展

# 通过 -v 容器内路径:ro rw 改变读写权限
ro #read only 只读
rw #read write 可读可写

# 一旦设置了容器权限,容器对我们挂载出来的内容就有限定了
docker 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.4初始Dockerfile

Dockerfile就是用来构建docker镜像的构建文件、命令脚本

通过这个脚本可以生成镜像,镜像是一层一层的,脚本一个个的命令,每个命令都是一层

# 创建一个dockerfile文件,名字可以随便 建议Dockerfile
# 文件中的内容 指令(大写) 参数
FROM centos

VOLUME ["volume01","volume02"]

CMD echo "----end----"
CMD /bin/bash
#这里的每个命令,就是镜像的一层!

docker build -f /dockerfile -t kuangshen/centos:v1.0 .
# 启动容器

这个卷和外部有一个同步的目录

查看一下挂载的路径

测试一下刚才的文件是否同步

这种方式之后使用的很多,因为 通常我们会构建自己的镜像

假设构建镜像的时候没有挂载卷,要手动镜像挂载 -v 卷名:容器内路径

6.5 数据卷容器

多个mysql同步数据

# 启动三个容器,通过我们自己写的容器
docker run -it --name docker01 kuangshen/centos:1.0

# 此时删除容器docker01,docker02和docker03依旧可以访问这个文件
拷贝的概念

多个mysql实现数据共享

docker run -d -p 3306:3306 -v /etc/mysql/conf.d  -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7

docker run -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01  mysql:5.7
# 这个时候,可以实现两个容器数据同步!

结论

  • 容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止

  • 但是一旦持久化到了本地,这个时候本地的数据是不会删除的

7. DockerFile

dockerfile是用来构建docker镜像的文件,命令参数脚本

7.1 构建步骤

  1. 编写一个dockerfile文件
  2. docker build构建成为一个镜像
  3. docker run 运行镜像
  4. docker push 发布镜像(docker hub,阿里云镜像仓库)

很多官方镜像都是基础包,很多功能都没有,我们通常自己搭建自己的镜像

7.2 Dockerfile构建过程

7.2.1 基础知识:

  1. 每个保留关键字(指令)都必须是大写字母
  2. 从上到下顺序执行
  3. 表示注释(#)
  4. 每个指令都会创建提交一个新的镜像,并提交

Dockerfile是面向开发的,以后发布项目,做镜像,就需要编写dockerfile文件

Docker镜像逐渐成为企业交付的标准

Dockerfile:构建文件,定义了一切的步骤,源代码

Dockerimages:通告Dockerfile构建生成的镜像,最终发布运行的产品

Docker容器:容器就是镜像运行起来提供服务

7.3 Dockerfile指令

FROM              # 基础镜像,一切从这开始构建
MAINTAINER 		  # 镜像是谁写的,姓名+邮箱
RUN				  # 镜像构建的时候需要运行的命令
ADD				  # 添加内容
WORKDIR			  # 镜像的工作命令
VOLUME     		  # 挂载的目录
EXPOSE			  # 指定暴露端口		  
CMD				  # 指定容器启动的时候运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT        # 指定这个容器启动的时候要运行的命令可以追加命令
ONBUILD			  # 当构建一个被继承的 dockerfile ,这个时候就会运行ONBUILD的指令,触发指令
COPY              # 类似ADD,将我们的文件拷贝到镜像中
ENV				  # 构建的时候设置环境变量

7.4 实战测试

Docker Hub中99%镜像都是从这个基础镜像过来的 FROM scratch,然后配置需要的软件和配置来进行构建

7.4.1 创建一个自己的centos

# 1.编写Dcokerfile文件
vim mydockerfile-centos

FROM centos
MAINTAINER z<419@qq.com>

ENV MYPATH /usr/loacl
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "----end----"
CMD /bin/bash

# 2.通过这个文件构建镜像
# 命令:docker build -f dockerfile文件路径 -t 镜像名:[tag] .
docker build -f mydockerfile-centos -t mycentos:0.1 .

# 3.测试运行

我们可以通过 docker history+镜像id 列出本地镜像的变更历史

我们平时拿到一个镜像,可以研究一下他是怎么做到的

7.4.2 CMD和ENTRYPOINT的区别

CMD			# 指定这个容器启动的时候要运行的命令,只有最后一个生效,可被替代
ENTRYPOINT  # 指定这个容器启动的时候要运行的命令,可以追加命令

测试CMD

# 编写dockerfile文件
vi dockerfile-cmd-test
FROM centos
CMD ["ls","-a"]

# 构建镜像
docker build -f dockerfile-cmd-test -t cmdtest .

# RUN运行,发现我们的ls -a命令生效
docker run dd8e4401d72f

# 想追加一个命令 -l,成为ls -al
docker run dd8e4401d72f -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-cmd-entrypoint
FROM centos
ENTRYPOINT ["ls","-a"]

$ docker build -f dockerfile-cmd-entrypoint -t entrypoint-test .

$ docker run 3c4c9621ed91   
.
..
.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 ....

7.5 实战测试:Tomcat镜像

1. 准备镜像文件 tomcat 压缩包,jdk的压缩包
2. 编写dockerfile文件,官方命名Dockerfile,build会自动寻找这个文件,不需要再-f指定

FROM centos 
MAINTAINER chao      # 名字

COPY readme.txt /usr/local/readme.txt #复制文件

ADD jdk-8u231-linux-x64.tar.gz /usr/local/ #复制解压
ADD apache-tomcat-9.0.35.tar.gz /usr/local/ #复制解压

RUN yum -y install vim

ENV MYPATH /usr/local #设置环境变量
WORKDIR $MYPATH #设置工作目录

ENV JAVA_HOME /usr/local/jdk1.8.0_11 #设置环境变量
ENV CLASSPATH $JAVA_HOME/bin/dt.jar:$JAVA_HOME/lib/tools.jar #设置环境变量 分隔符是:
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.35 #设置环境变量
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.35 #设置环境变量
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin

EXPOSE 8080 #设置暴露的端口
CMD /usr/local/apache-tomcat-9.0.35/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.35/bin/logs/catalina.out # 设置默认命令

3. 构建镜像
docker build -t diytomcat .

4. 运行
$ docker run -d -p 9090:8080 --name kuangshentomcat -v /home/kuangshen/build/tomcat/test:/usr/local/apache-tomcat-9.0.35/webapps/test -v /home/kuangshen/build/tomcat/tomcatlogs/:/usr/local/apache-tomcat-9.0.35/logs diytomcat

5、访问测试

6、发布项目(由于做了卷挂载,我们直接在本地编写项目就可以发布了!)
  1. 发布项目
vi web.xml 

  <?xml version="1.0" encoding="UTF-8"?>
  <web-app xmlns="http://java.sun.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                               http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
           version="2.5">

  </web-app>
vi index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JC</title>
</head>
<body>
Hello World!<br/>
<%
sysem.out.println("---my test web logs---")
%>
</body>
</html>

7.6 发布镜像

提交的时候也是按照镜像的层级来进行提交的

7.6.1 DcokerHub

  1. https://hub.docker.com 注册自己的账号
  2. 确定这个账号可以登录
  3. 在我们服务器上提交自己的镜像
  4. 登录完毕之后就可以提交镜像了,docker push
$ docker login --help
Usage:  docker login [OPTIONS] [SERVER]

Log in to a Docker registry.
If no server is specified, the default is defined by the daemon.

Options:
  -p, --password string   Password
      --password-stdin    Take the password from stdin
  -u, --username string   Username

# 登录
dokcer login -u 用户名

# 上传镜像
docker push 镜像名

# push镜像的问题
 会发现push不上去,因为如果没有前缀的话默认是push到 官方的library
# 解决方法
1. 第一种 build的时候添加你的dockerhub用户名,然后在push就可以放到自己的仓库了
$ docker build -t chengcoder/mytomcat:0.1 .

2. 第二种 使用docker tag 然后再次push
$ docker tag 镜像id chengcoder/mytomcat:1.0 #然后再次push

7.6.2 阿里云

  1. 登录阿里云
  2. 找到容器镜像服务
  3. 创建命名空间

  1. 创建容器镜像

  1. 浏览阿里云

阿里云容器镜像的就参考官方地址

7.7 docker流程小结

8. Docker网络

8.1 理解Docker0

三个网络

# 问题:docker 是如何处理容器网络访问的

# 测试  运行一个tomcat
docker run -d -P --name tomcat01 tomcat

# 查看容器的内部的网络地址   ip addr                               

       
docker exec -it 容器id ip addr

# 查看容器内部网络地址 发现容器启动的时候会得到一个 eth0@if551 ip地址,docker分配!
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
       
# 思考? linux能不能ping通容器内部! 可以 容器内部可以ping通外界吗? 可以!
$ 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.069 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.074 ms

8.1.1 原理

  • 我们每启动一个docker容器,docker就会给docker容器分配一个ip ,我们只要安装了docker,就会有一个网卡docker0 桥接模式,使用的技术是 evth-pair技术
  1. 再次测试ip addr

  1. 再启动一个容器测试,发现又多了一对网卡

# 我们发现这个容器带来的网卡,都是一对一对出现的
# evth-pair 就是一对的虚拟设备接口,都是成对出现的,一段连着协议,一段彼此相连
# 正因为有这个特性,evth-pair 充当一个桥梁,连接各种虚拟网络设备的
# Openstack,Docker容器之间的连接,OVS的连接,都是使用evth-pair技术
  1. 我们测试 tomcat01 和 tomcat02 可以ping通
docker exec -it tomcat02 ping 172.18.0.2

# 结论:容器和容器之间是可以相互ping通的

结论: tomcat01 和 tomcat02 是共用的一个 docker0

所有的容器不指定网络的情况下,都是通过docker0通信的,docker会给我们的容器分配一个默认的可用IP

8.1.2 小结

  • Docker使用的是Linux的桥接,宿主机中是一个Dokcer容器的网桥 docker0

  • Dcoker中的所有的网络接口都是虚拟的,虚拟的转发效率高

  • 只要容器删除,对应网桥一对就都没了

场景:编写了一个微服务,项目不重启,数据库 IP 换掉了,如何用名字来进行访问容器

$ docker exec -it tomcat02 ping tomca01   # ping不通
ping: tomca01: Name or service not known
# 如何解决?
通过 --link 解决了网络连通问题


# 运行一个tomcat03 --link tomcat02 
$ docker run -d -P --name tomcat03 --link tomcat02 tomcat
5f9331566980a9e92bc54681caaac14e9fc993f14ad13d98534026c08c0a9aef

# 用tomcat03 ping tomcat02 可以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不通


探究:inspect

# 查看hosts 配置

  • --link 就是在我们hosts配置中增加了一个 172.18.0.3 tomcat02 312857784cd4

  • 现在已经不建议使用 --link 了

docker0的问题:不支持容器名连接网络

8.3 自定义网络

查看所有的docker 网络

网络模式:

  1. bridge:桥接(默认)

      	2.	none:不配置网络
                	3.	host:和宿主机共享网络
                          	4.	container:容器网络互通(用的少,局限大)
    

测试:

# 我们直接启动的命令默认有--net bridge,而这个就是我们的docker0
docker run -d -P --name tomcat01 tomcat
等价于---> docker run -d -P --name tomcat01 --net bridge tomcat

# docker0 特点:默认bridge,域名不能访问,  --link可以打通连接,但不推荐使用

# 我们可以自定义一个网络

自定义一个网络

# --driver  bridge
# --subnet 192.168.0.0/16
# --gateway 192.168.0.1
docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet

docker network ls

# 我们的网络就创建好了
docker network inspect mynet

# 测试
docker run -d -P --name tomcat-net-01 --network mynet tomcat
docker run -d -P --name tomcat-net-02 --network mynet tomcat


# 自定义的网络可以直接ping 通, 不需要使用 --link

  • 自定义的网络 docker都已经帮我们维护好了对应的关系,推荐我们平时这样使用网络

好处:

redis:不同的集群使用不同 的网络,保证集群是安全和健康的

mysql:不同的集群使用不同的网络,保证集群是安全和健康的

8.4 网络连通

# 测试打通 tomcat01 - mynet
docker network connect mynet tomcat01

# 连通之后就是将 tomcat01 放到了 mynet 网络下

# 一个容器两个ip地址

  • 结论:假设要跨网络操作别人,就需要使用docker network connect 连通

8.5 实战:部署Redis集群

# 创建网卡
docker network create redis --subnet 172.38.0.0/16
# 通过脚本创建六个redis配置
for port in $(seq 1 6);
do 
mkdir -p /mydata/redis/node-${port}/conf
touch /mydata/redis/node-${port}/conf/redis.conf
cat << EOF >> /mydata/redis/node-${port}/conf/redis.conf
port 6379
bind 0.0.0.0
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.38.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
appendonly yes
EOF
done

# 通过脚本运行六个redis
for port in $(seq 1 6);
docker run -p 637${port}:6379 -p 1667${port}:16379 --name redis-${port} 
-v /mydata/redis/node-${port}/data:/data 
-v /mydata/redis/node-${port}/conf/redis.conf:/etc/redis/redis.conf 
-d --net redis --ip 172.38.0.1${port} redis:5.0.9-alpine3.11 redis-server /etc/redis/redis.conf


docker exec -it redis-1 /bin/sh #redis默认没有bash

# 创建集群
redis-cli --cluster create 172.38.0.11:6379 172.38.0.12:6379 172.38.0.13:6379 172.38.0.14:6379 172.38.0.15:6379 172.38.0.16:6379  --cluster-replicas 1
原文地址:https://www.cnblogs.com/j-chao/p/13212436.html