# docker
**Repository Path**: leisurely-leisurely/docker
## Basic Information
- **Project Name**: docker
- **Description**: 笔记
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2022-10-12
- **Last Updated**: 2022-10-12
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 专业名词
虚拟技术
容器技术
联合文件系统
>一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下
签名
远程仓库
本地仓库
镜像
容器
隔离
---
# 常用linux命令
**vim**
>删除全部:先gg然后dG
>
>全部复制:先gg然后yG
>
>删除一行:dd
>
>复制一行:yy
echo、cat、>>、pwd、cd、ls、cp、mv、rm、df、mount、umount、touch、mkdir、rm、chmod、|、grep、route、ifconfig、netstat
**systemctl start/status等 服务名**
ps、kill、ping
# CentOS8安装
**步骤:**
>1. 到CentOS官方https://www.centos.org/download/mirrors/下载centos的ios镜像。seacher搜索china,找到Alibaba Cloud Computing,点击对应的Mirror,到阿里云镜像下载对应的centos版本,即7.9.2009版本 -> ioss/ -> X86_64 -> [CentOS-7-x86_64-DVD-2207-02.iso](http://mirrors.aliyun.com/centos/7.9.2009/isos/x86_64/CentOS-7-x86_64-DVD-2207-02.iso?spm=a2c6h.25603864.0.0.17ba6aeaBbg5Vv)。下载完成后安装
>2. https://blog.csdn.net/m0_60744481/article/details/122081755
---
# Docker
dockerHub:类似于github的一样,不过dockerhub拉推都是镜像https://hub.docker.com/
**docker官方文档**:
https://docs.docker.com/desktop/
https://docs.docker.com/reference/
---
## 问题
1. 如果防火墙关闭或者禁用,都要重启docker。
>这时因为在启动docker的时候会自动在iptables中注册一个链,通过防火墙的链也可以找到其注册的信息,主要注册这些链,是docker中的容器为了暴露端口而使用的
2.
---
## docker安裝
**步骤:**
>1. 确保 yum 包更新到最新。
>
> ```shell
> sudo yum update
> ```
>
>2. 安装docker所需的软件包yum-config-manager
>
> ```shell
> sudo yum install -y yum-utils device-mapper-persistent-data lvm2
> ```
>
>3. 添加一个远程仓库。类似git的git remote add操作
>
>4. 下载指定的docker版本
>
> ```shell
> # 获取源中docker的所有版本
> yum list docker-ce --showduplicates | sort -r
> # 下载指定的docker版本
> sudo yum install docker-ce-18.03.1.ce-1.el7.centos docker-ce-cli-18.03.1.ce-1.el7.centos containerd.io
> # 下载最新的docker版本
> sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin
> ```
>
>5. 测试下载成功。
>5. docker version查看docker版本号
>
> ```shell
> # 启动docker服务
> sudo systemctl start docker
> # 创建并运行hello-world容器
> sudo docker run hello-world
> ```
>
**配置镜像加速地址**
```shell
# 创建docker的配置文件目录
sudo mkdir -p /etc/docker
# 创建一个docker的远程访问配置文件daemon.json
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["http://hub-mirror.c.163.com","https://reg-mirror.qiniu.com"]
}
EOF
# 重启服务
sudo systemctl daemon-reload
# 重启docker
sudo systemctl restart docker
# 如果有daemon.json文件,则编辑该文件
vim /etc/docker/daemon.json
# docker镜像加速
{
"registry-mirrors": [
"https://yxhvs3zj.mirror.aliyuncs.com",
"http://hub-mirror.c.163.com",
"https://reg-mirror.qiniu.com",
"https://docker.mirrors.ustc.edu.cn/"
]
}
CentOS 7 x86_64/Packages
```
**删除docker的所有依赖**
```shell
# 删除docker的依赖
sudo yum remove docker docker-client docker-client-latest docker-common \
docker-latest docker-latest-logrotate docker-logrotate docker-engine
# 删除docker目录资源
rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
```
**禁用linux防火墙**
```shell
# 停止防火墙服务
systemctl stop firewalld
# 禁用防火墙
systemctl disable firewalld
```
**docker的portainer可视化界面**
https://zhuanlan.zhihu.com/p/530337389
```shell
# 下载protainer镜像
docker pull portainer/portainer
# 注意:不能更改其数据卷位置。还会占用一个9443端口,请参考官方文档:https://docs.portainer.io/start/install/server/docker/linux
docker run -d -p 8000:8000 -p 9000:9000 --net="bridge" --name=portainer --privileged --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
```
**docker的Rancher可视化界面**
---
## 概述
**docker**
>Docker 是一个开源的应用容器引擎,基于 [Go 语言](https://www.runoob.com/go/go-tutorial.html) 并遵从 Apache2.0 协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。
>
>**docker的运行:**
>
>当docker run 时,会从先本地仓库中获取镜像,
>
>如果获取到,则直接创建一个新容器,并运行。
>
>如果获取不到,则会去远程仓库中获取镜像文件,如果远程仓库获取得到,则会下载到本地仓库,在创建一个新容器并运行,如果远程仓库获取不到,则返回一个错误。
>
>Docker 在隔离的容器中运行进程。 容器是一个过程 它在主机上运行。 主机可以是本地的或远程的。 当运营商 执行 `docker run`,运行的容器进程被隔离在 它有自己的文件系统、自己的网络和自己的 独立于主机的进程树。
**docker的应用场景:**
- Web 应用的自动化打包和发布。
- 自动化测试和持续集成、发布。
- 在服务型环境中部署和调整数据库或其他的后台应用。
- 从头编译或者扩展现有的 OpenShift 或 Cloud Foundry 平台来搭建自己的 PaaS 环境。
**docker优点**
>1. 快速,一致地交付您的应用程序,Docker 允许开发人员使用您提供的应用程序或服务的本地容器在标准化环境中工作,从而简化了开发的生命周期。
>2. 响应式部署和扩展。基于容器的平台,允许高度可移植的工作负载。Docker 容器可以在开发人员的本机上,数据中心的物理或虚拟机上,云服务上或混合环境中运行。可移植性和轻量级的特性,还可以使您轻松地完成动态管理的工作负担,并根据业务需求指示,实时扩展或拆除应用程序和服务。
>3. 在同一硬件上运行更多工作负载。
**docker的3个基本概念:**
- **镜像(Image)**:Docker 镜像(Image)用于创建 Docker 容器的模板,是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境的软件,它包含运行某个软件所需要的所有内容。本质上是一个联合的文件系统UnionFS。
>**注意:**==在这联级文件系统中容器层是建立镜像层之上的,镜像层是只读的,是不能被修改的,而我们运行容器里所有被修改的内容,均是写在镜像层的基础上添加的一层容器层里。==
>
>**分层的原因:**
>
>1. 分层最大的一个好处就是共享资源
>2. 有多个镜像都从相同的base镜像构建而来,那么宿主机只需在磁盘上保存一份base镜像;
>3. 同时内存中也只需加载一份base镜像(根据标识来讲),就可以为所有容器服务了,而且镜像的每一层都可以被共享。
>
>比如:一个tomcat镜像有500多m,但是如果我们之前下过centos、jdk等其他镜像,我们下载tomcat时,就会很快,这是因为tomcat的镜像分层由顶到底:tomcat->jdk8->centos->kernel。当我们下载过centos时,则centos就不需要下载。
- **容器(Container)**:是镜像的创建运行的,可以独立运行一个或者一组应用。
- **仓库(Repository)**:仓库可看成一个代码控制中心,用来保存镜像。比如:github远程仓库和本地仓库、maven仓库等
**镜像和容器的关系:**
>容器是独立运行的一个或一组应用,是镜像运行时的实体。就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。
**传统虚拟机与Docker虚拟化技术的对比**
| 领域 | 传统虚拟机 | Docker虚拟化 |
| -------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 应用交付与部署 | 每发布一个应用程序,都需要走一遍流程 | 集装箱式交付,整体交付 |
| 资源消耗 | 传统虚拟机要具备独立的虚拟CPU、内存、操作系统,如果我们有10个虚拟机,则需要安装10个操作系统,虚拟出来10个CPU、内存等,因此造成大量的资源浪费 | 容器可以运行相同的一个操作系统内核,让一个容器的消耗与一个进程一样 |
| 启动 | 虚拟机硬件需要初始化,需要启动时间 | 没有虚拟机硬件初始化过程,开箱即用 |
| 应用安装 | 需要大量的安装包及安装过程,如下载完整镜像也非常耗费时间 | 统一仓库拉取,结构简单,拉取速度快 |
| 故障 | 虚拟机内应用崩溃,理论上不会影响其它虚拟机以及上面运行的应用的,除非是硬件或者Hypervisor有Bug | 因为共用内核,只靠cgroup隔离,应用之间的隔离是不如虚拟机彻底的,如果某个应用运行时导致内核崩溃,所有的容器都会崩溃 |
---
## 命令
**docker info**
>查看docker信息。比如:本地仓库镜像个数、容器个数、运行容器个数、docker根目录等等
---
### 镜像
**docker images**
>查看docker的本地仓库里的所有镜像
**docker search 搜索内容**
>会dockerhub远程仓库上搜索我们指定的内容的所有镜像文件
**docker pull 镜像name[:版本号]**
>从远程仓库中下载指定版本的镜像到本地仓库中。默认版本号为latest最新
>
>docker下载镜像采用的是分离式下载,下载的文件是以联合文件系统方式存储
**docker rmi 镜像id/镜像名**
>删除docker中指定的镜像或者一组镜像名为指定的镜像
>
>```shell
># 利用liunx的符号$(命令),将命令执行的结果放入$()所在的位置
># docker images -aq获取所有的镜像id,即变成docker rmi 镜像id1 镜像id2 ...
>docker rmi $(docker images -aq)
>```
**docker image inspect 镜像id/镜像名:版本号**
>查看镜像的信息
---
### 容器
**docker run [OPTIONS] 镜像name[:TAG|@DIGEST] [命令] [ARG...]**
>根据镜像创建一个新的容器并运行一个命令
>
>**参数:**
>
>OPTIONS操作员可以添加或覆盖 由开发人员设置的图像默认值
>
>* **-a stdin:** 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;
>
>* **-d:** ==后台运行容器,并返回容器id/容器name;==注意:如果无法后台运行(后台模式启动后自动结束),则以交互式方式的后台运行
>
>* **-i:** ==以交互模式运行容器,通常与 -t 同时使用;==
>
>* **-t:** ==为容器重新分配一个伪输入终端,通常与 -i 同时使用;常用/bin/bash使用==
>
>* **-P:** 随机端口映射,容器内部端口**随机**映射到主机的端口
>
>* **-p:** ==指定端口映射,格式为:主机(宿主)端口:容器端口==
>
>* **--ip 指定docker网络内特定的ip地址:**指定docker网络内特定的ip地址
>
>* **--name="nginx-lb":** 为容器指定一个名称;
>
>* **--dns 8.8.8.8:** 指定容器使用的DNS服务器,默认和宿主一致;
>
>* **--dns-search example.com:** 指定容器DNS搜索域名,默认和宿主一致;
>
>* **-h "mars":** 指定容器的hostname;
>
>* **-e 键=值:** ==修改环境变量;==
>
>* **--env-file=[]:** ==从指定文件读入环境变量;==
>
>* **--cpuset="0-2" or --cpuset="0,1,2":** 绑定容器到指定CPU运行;
>
>* **-m :**设置容器使用内存最大值;
>
>* **--net="bridge" 或者 --net bridge:** ==指定容器的网络连接类型,支持 bridge通过网桥二层/host/none/container: 四种类型;==
>
>* **--link=[]:** 添加链接到另一个容器;
>
>* **--expose=[]:** 开放一个端口或一组端口;
>
>* **--volume , -v 主机目录:容器目录[:ro或者rw]:** ==绑定一个卷==
>
> * **-from 容器id/容器name:**挂载的卷是指定的容器挂载卷。即2个容器将共用指定的数据卷,也称为数据卷容器
>
>* **--privileged:=**=授予该容器扩展权限==
>
>* **--rm:**当容器停止时,会自动删除容器,常用于测试。
>
>* **--restart=no :**指定容器退出时,docker怎么处理容器
>
> >**参数值:**
> >
> >no:默认值,容器退出时,docker不自动重启容器
> >
> >always :容器退出时,docker会总是自动重启这个容器
> >
> >on-failure:重启次数:表示容器的退出状态码非0(非正常退出)时,docker会自动重启容器,当重启次数超过指定的次数时,则不会自动重启
> >
> >unless-stopped:容器退出时总是重启,但是不考虑docker守护进程运行时就已经停止的容器
>
>*
>
>
>
>
**docker create [OPTIONS] IMAGE[:TAG|@DIGEST] [COMMAND] [ARG...] **
> 根据镜像创建一个新的容器但不启动它
**docker start/restart/stop 容器id/容器name**
>启动、重启、停止指定容器(已经创建好的容器,即不用去拉取镜像)的运行。其实是docker container start等操作
**docker kill 容器id/容器name**
>杀掉一个运行中的容器。其实是docker container kill 操作
**docker rm 【option】 容器id/容器name**
> 删除一个或多个容器。其实是docker container rm 操作
>
> **参数:**
>
> option
>
> - **-f :**通过 SIGKILL 信号强制删除一个运行中的容器。
> - **-l :**移除容器间的网络连接,而非容器本身。
> - **-v :**删除与容器关联的卷。
**docker exec 【option】 容器id/容器name 命令**
>在运行的容器中执行命令
>
>**参数:**
>
>option
>
>- **-d :**分离模式: 在后台运行
>- **-i :**即使没有附加也保持STDIN 打开
>- **-t :**分配一个伪终端
>
>```shell
># 启动在容器内部新建一个终端,来执行命令
>docker exec -it mynginx /bin/bash
># 在容器内部执行脚本
>docker exec -it mynginx /bin/sh /root/runoob.sh
>```
**docker attach 容器id/容器name**
>进入docker容器内`正在执行的终端`里执行命令。也可以进去修改配置。
**docker inspect 容器id容器name**
>查看指定的容器的所有信息。比如:容器网络配置、容器状态、日志、配置等存放位置、-v绑定卷所(mounts)挂载的目录
**docker ps**
>查看运行过的docker容器的状态
>
>**参数:**
>
>* -a:查看所有容器
>* -q:只查看容器id
>
>容器状态:
>
>* created(已创建)
>* restarting(重启中)
>* running(运行中)
>* removing(迁移中):
>* paused(暂停):被暂停的容器不再对外服务,但是仍然占用宿主机资源。可以再次被启动。
>* exited(停止):不再提供服务,不占用宿主机资源。可以再次被启动。
>* dead(死亡):
**docker logs -t 容器id/容器name**
>查看指定容器的日志信息,且附带日志的时间
docker top 容器id/容器name
>查看指定容器的进程信息
---
### 操作
**docker commit 【option】 容器id 镜像name[:版本号]**
>将指定的容器id打包指定镜像名和版本号的镜像,并提交到本地仓库中
>
>**参数:**
>
>option
>
>* -a:作者
>* -m:提交的消息,相当于git commit "消息"
>* -c:对创建的映像应用Dockerfile指令
>
>
**docker cp 容器id/容器name:/容器内目录 复制到本机的哪个位置上**
>复制docker容器里的数据。常与docker run -v 数据卷使用,可以直接使用copy的数据来作为容器
>
**docker load -i 镜像的备份文件位置**
>将指定镜像备份文件加载进本地仓库中
**docker save -o 镜像保存到哪个目录下 镜像 ...**
>将指定的镜像保存备份到指定目录下
---
## 数据卷
**情景:**
1. 删除容器,容器里的数据就全都没了。
2. 由于需要各个容器间数据要共享一致,但容器间的数据是相互隔绝的。比如:mysql
**使用方式:**使用docker run -v [挂载的本地目录:]容器目录或者文件[:ro或者rw]
> 如果本地目录是/开头,则是`指定路径挂载`。挂载到指定的目录下。
>
> 如果本地目录没有以/开头,则是`具名挂载`。这时是挂载到/var/lib/docker/volumes/本地目录xxx
>
> 如果没有本地目录,则是`匿名挂载`。也是挂载到/var/lib/docker/volumes/匿名目录xxx
>
> **参数:**
>
> ro:代表只读readonly,即在容器里是无法修改该卷的,只能通过宿主机来改变该卷的内容
>
> rw:代表可读写readwrite,即容器和宿主机都可以改变卷的内容
**docker数据卷命令**
>**docker volume create**
>
>创建卷
>
>**docker volume inspect 卷名**
>
>查看指定卷信息。比如:创建时间、挂载的本地目录的位置
>
>**docker volume prune**
>
>删除所有未使用的本地卷
---
## docker网络
1. docker容器里使用的是veth技术来实现虚拟网卡。
2. docker0是与虚拟机连通,而容器是通过指定的网络方式(自定义网络、host、bridge、null等)连通docker0
**docker network inspect 网络名**
>查看指定网络的详细信息
**docker network create 【option】 网络名**
>确保子网不重叠。如果重叠的话网络创建失败,并且引擎会返回错误。
>
>创建一个自定义网络。
>
>**参数:**
>
>option:
>
>* **-d 网络适配器类型**:指定自定义网络的网络适配器类型,比如有:bridge与虚拟机是桥接关系、host与虚拟机是仅主机模式、null。默认是桥接
>
>* **--driver=网络适配器类型**:跟-d一样
>
>* **--gateway 自定义网络的网关ip:**
>
>* **--subnet 子网的网络号**:==指定子网络值。 在桥接网络上,只能创建单个子网。即自定义网卡的ip,及其连接到该网卡上的容器所用的ip网络号==
>
> ```shell
> docker network create --driver=bridge --subnet=192.168.146.0/24 env-net
> ```
>
>
**docker network connect 网络**
>==由于2个docker自定义网络是互不相通的,如果需要他们的容器彼此通信,则需要通过该命令来连通==
**docker network ls**
>列出当前docker中所有网络
**docker network rm 网络名/id**
>删除网络
**docker容器配置固定ip**
>https://www.jb51.net/article/244501.htm
>
>**步骤:**假设虚拟机ip地址为192.168.1.105
>
>1. 创建自定义网络
> ```shell
> # docker-br0与虚拟机是桥接模式,即docker-br0的ip一定与虚拟机同网段
> # docker-br0网络下的容器一定属于172.172.0.0的网络号子网掩码为255.255.255.0
> docker network create --subnet=172.172.0.0/24 docker-br0
> ```
>
>2. 在你自定义的网段选取任意IP地址作为你要启动容器IP
> ```shell
> docker run -i -d --net docker-br0 --ip 172.172.0.10 --name nginx
> ```
>
>
---
# 搭建常用的环境
---
## 网络知识
测试数据效果:
| 主机 | 网络模式 | 虚拟机 | 网络模式 | docker网卡 | 网络模式 | 容器 |
| ------------------------------------------------------------ | -------- | ------ | -------- | ---------- | ---------------- | ---- |
| 能通过访问虚拟机ip:容器端口访问到容器。
如果要访问到容器内部,则需要配置路由 | 仅主机 | | nat | docker0 | host | |
| 能通过访问虚拟机ip:容器端口访问到容器
如果要访问到容器内部,则需要配置路由 | 仅主机 | | nat | docker0 | 桥接 | |
| 能通过访问虚拟机ip:容器端口访问到容器
如果要访问到容器内部,则需要配置路由 | 仅主机 | | nat | docker0 | 自定义网络(桥接) | |
| 同理 | nat模式 | | | | | |
```shell
vim /etc/sysctl.conf
#配置转发
net.ipv4.ip_forward=1
# 如果显示net.ipv4.ip_forward=1说明配置ip4转发功能开启
sysctl net.ipv4.ip_forward
vim /etc/sysconfig/network-scripts/ifcfg-ens33
systemctl stop firewalld
systemctl disable firewalld
systemctl restart sshd
systemctl status sshd
# add 增加路由 del 删除路由 via 网关出口 dev 网关出口 物理设备名
# 查看路由
route
ip route
# 删除路由
route del -net 192.168.210.0/24
# 添加主机路由
route add -host ip地址 gw 网关地址ip即当访问该网络时自动发送给该网关地址
# 添加网络路由
route add -net 网络号 netmask mask地址 gw 网关地址ip即当访问该网络时自动发送给该网关地址
# 下载网络工具,可以配置容器里的网络
yum install net-tools
# 添加主机路由
ip route add 对方容器所在的ip网段/子网掩码 via 对方虚拟机ip dev 通过哪个网卡通信
ip route add 172.172.1.0/24 via 192.168.1.106 dev eno16777736
```
**主机路由**:把一台主机当做路由。仅仅只能表示一台,所以子网掩码要用255.255.255.255
```shell
route add –host 192.168.168.119 gw 192.168.168.1
```
**默认路由**:当找不到路由时,则默认发给该路由
**网络路由**:指的某一个网络的,即ping 某个网络就发送给该路由。
```shell
route add -net 192.168.210.0 netmask 255.255.255.0 gw 192.168.230.1
```
**桥接**
>OSI网络模型的链路层的地址,对网络数据包包装成数据帧进行存储转发(单播、多播、广播)的过程。是一种以Mac地址来作为判断依据将网络划分成不同物理段的技术。
>
>**注意点**:
>
>1. 虚拟机与宿主机同网段,且网关与宿主机一样即可。这时因为交换机只会广播同网段下的主机,进行存储转发
>
>**宿主机、虚拟机与桥接的网关路由的连接图,请参考笔记图片:**
>
>1. 由于网关路由会记录下所有连接该网络的内部主机,而且还有与外网通信路由记录
**NAT**
>是指网络地址转换。一般外网做不到访问nat内网,因为外网的路由表基本不知道路由给谁,但是nat设备就知道路由给谁,所以需要外网能访问内网,则必须添加路由表,路由到给nat设备即可外网访问内网。
>
>主机网卡路由表只有nat设备的网络地址,而没有nat内网的地址,所以是无法通过主机网卡访问内网的。
>
>VM8与主机相连、主机可以与VM8通信,VM8如果属于内网的话,则可以设置一个默认路由,即nat设备,将主机访问VM8网段的地址均发给VM8,VM8路由表发给默认路由nat设备,nat设备在发给指定虚拟机。
>
>**注意点:**
>
>* 如果虚拟机与宿主机开启端口映射,那么该宿主机的端口会被虚拟机的抢占
>* VM8网络适配器->配置->高级->jumbo packet设置为Enable(9014)==
>* VM8必须与内网同网段,而且Vm8的默认路由必须与虚拟机的默认路由(nat设备)一样
>
>**虚拟机的nat模式的连接图,请参考笔记图片:**
>
>* ==VM8必须与内网同网段的原因:VM8是与主机相连,即路由表有一个网络地址是直接路由给VM8,所以主机一定ping得通VM8的网络地址下的所有ip,而VM8与内网同网段的话,则可以指定网关路由为nat设备,而nat设备知道内部的所有虚拟机,这时主机访问内网的虚拟机了地址,会路由给Vm8,vm查看没有,则发送给默认路由nat设备,nat设备在发送给指定虚拟机==
>* ==VM8必须与内网同网段,而且VM8的网关必须与虚拟机的网关一致,如果不一致或者关闭VM8,则虚拟机还是可以上网,虚拟机也ping得通主机,主机ping不通虚拟机,这时因为主机是通过VM8与内网通信(主机直接访问内网地址)的,而内网里的虚拟机是可以通过主机的网卡与主机通信,也可以通过VM8与主机通信。而内网的虚拟机可以通过nat地址转换给主机网卡与外网通信,所以内网虚拟机上不上得了网是主机网卡和nat设备决定的==。
>* 如果nat模式访问不了虚拟机,记得将VM8网络适配器->配置->高级->jumbo packet设置为Enable(9014)。原因不明
>
>**端口映射:**是指内网的ip地址:端口号映射到宿主机的端口号上,会占用宿主机的端口号
>
>比如:主机ip:192.168.24.161 255.255.255.0。主机与虚拟机是nat模式,下面是端口转发映射表(nat设备VM8)
>
>| 主机端口 | 虚拟机ip地址 |
>| -------- | ------------------- |
>| 8848 | 192.168.16.132:8848 |
>
>当我们192.168.24.0网段下的主机,访问192.168.24.161:8848时,就相当于访问虚拟机的 192.168.16.132:8848地址。注意:这时主机的8848端口就会被占用着。
>
**主机模式**
>虚拟机被包含在VM1所在的专用网络内,即虚拟机是VM1的网段下的ip,可以是其子网
>
>**注意点:**
>
>* 虚拟机的主机模式很傻逼的,如果按下面都配置了不能网上或者虚拟机ping自己配的网关,则可能是你电脑开机时,没有连上网络,后面再连上网络,再开启虚拟机,或者断网了后重新连上
>* 虚拟机必须属于VM1的子网或者同网段的ip,虚拟机的网关必须配置为VM1的ip地址
>* 宿主机的网卡必须共享连接给Vm1
>* 其他主机访问不到宿主机的内网,除非配置路由
>* ==VMware Bridge Protocol点击√,不然vm1是不在虚拟机链路上的,所以会出现虚拟机自己配置的网关自己都ping不了==
>* 主机模式有时候很傻逼的,明明配置没错,而且之前还可以上网。这时只需要重启系统或者宿主机就可以了或者重新共享
>
>**特点:**
>
>1. 宿主机可以访问到虚拟机,虚拟机可以访问到宿主机,但其他主机访问不到虚拟机,但是可以通过配置路由访问到虚拟机。所以虚拟机网段完全属于宿主机的内网。
>
>**主机与虚拟机、VM1的网络连接关系,请参考笔记里的图片:**
>
>* ==虚拟机必须属于VM1的子网或者同网段的ip,这是因为虚拟机是靠VM1连接主机的路由进行上网的。所以虚拟机的网关必须配置为VM1的ip地址。==
>* 由于主机模式是与宿主机共享网络连接的,所以主机的网卡必须共享允许VM1网络连接到主机网卡上。==网络连接->WLAN右键->属性->共享->允许其他网络用户连接此计算机的Internet连接来连接网络->√,并且选择VM1网卡即可。==
>* ==由于主机模式共享网络连接,是VM1连接入主机的网卡,所以Vm1网段是只能由主机访问,即完全的内网,而与主机同网络下的其他主机是无法访问到该内网Vm1的。如果想要访问,则必须配置路由发送给该主机即可。==
**docker0网卡**
>**docker网络:**
>
>1. 如果虚拟机防火墙(防火墙工作最低层是网络层,也有应用层防火墙)开着,docker会将网络配置注册到防火墙里,这时,访问非桥接模式的容器均无法访问到,因为被防火墙给拦截了。而桥接模式可以访问到这时因为链路层。
>1. ==docker0网卡与虚拟机的网络连接方式是nat模式,虚拟机有着docker0网卡的内网路由表,即所有内网地址均会发给docker0,让docker0去发送给指定容器,所以虚拟机是可以ping到容器的。如果想要外网ping到容器,则必须让其路由发送到虚拟机。==
>
>**容器的网络:**
>
>* 桥接模式+NAT模式:==容器网络使用桥接,并且会端口映射到虚拟机上,这时因为docker0是与虚拟机nat连接的,而-p端口映射的是虚拟机与容器之间的==
>* 主机模式:与宿主机同一个ip地址,而且共用端口,所以虚拟机的端口会被占用
>
---
## mysql
**注意点:**
1. 如果本地主机连接不上docker部署的mysql,可能mysql默认不允许其他ip访问,可以通过修改配置来允许任意人访问
```shell
# 先启动msyql容器,并进入mysql容器内部
docker exec -it mysql /bin/bash
#执行一下命令
mysql -u root -p
123123
use mysql;
#方式1:
grant all privileges on . to root@'%';
flush privileges;
#方式2:
update user set Host = '%' where User ='root';
flush privileges;
select Host,User from user u where u.`User`="root";
ALTER USER "root"@"%" IDENTIFIED WITH mysql_native_password BY "root";
ALTER USER 'root'@'%' IDENTIFIED WITH MYSQL_NATIVE_PASSWORD BY '123123';
```
2.
**步骤:**
1. 去dockerhub上搜索mysql,看看mysql版本
2. 将mysql指定的版本下载到本地仓库
```shell
docker pull mysql:8.0.30
```
3. 根据mysql镜像创建容器,并配置好mysql配置
```shell
docker run -it --name mysql --net env-net -p=3306:3306 --ip=192.168.146.33 --privileged \
-e MYSQL_ROOT_PASSWORD=123123 \
-v /env/mysql/logs:/logs \
-v /env/mysql/conf:/etc/mysql/conf.d \
-v /env/mysql/data:/var/lib/mysql \
-d mysql:8.0.30
# 如果需要添加mysql配置文件,则直接放在下面指定的2个目录下即可
-v /env/mysql/conf:/etc/mysql/conf.d
# 如果需要查看mysql的日志文件,则在下面2个指定的目录下查看即可
-v /env/mysql/logs:/logs
# 如果要mysql的数据文件,则在下面的2个指定目录下
-v /env/mysql/data:/var/lib/mysql
```
4. 测试
```shell
docker exec -it mysql /bin/bash
mysql -u root -p
123123
或者在win上
mysql -u root -h 虚拟机的ens33的ip地址 -P mysql绑定的端口默认是3306 -p
123123
show databases;
```
---
## nginx
---
## redis
**步骤:**
1. 去dockerhub上搜索redis,看看redis版本
2. 将redis指定的版本下载到本地仓库
```shell
docker pull redis:7.0.5
```
3. 根据redis镜像创建容器,并执行redis-server命令
```shell
# 指定redis配置文件,启动redis服务。如果不加redis-server命令,默认是加上的,而且读取官方指定的目录下的配置文件
docker run --name redis1 --net="host" -p=6381:6381 -v /env/redis/config:/redis/config -d redis:7.0.5 redis-server /redis/config/redis.conf
```
4. 进入redis-cli客户端
```shell
docker exec -it redis1 /bin/bash
redis-cli
redis-sentinel 哨兵配置文件
```
**注意:**如果开启了主从复制就必须置cluster-enabled no,因为cluster里就已经有主从复制了。
**主从复制方式:**
```shell
# 主从复制
docker run --name redis-master --net="host" -p=6379:6379 -v /env/redis/config/master-slave:/redis/config -d redis:7.0.5 redis-server /redis/config/redis-master.conf
docker run --name redis-salve1 --net="host" -p=6380:6380 -v /env/redis/config/master-slave:/redis/config -d redis:7.0.5 redis-server /redis/config/redis-salve1.conf
docker run --name redis-salve2 --net="host" -p=6381:6381 -v /env/redis/config/master-slave:/redis/config -d redis:7.0.5 redis-server /redis/config/redis-salve2.conf
```
**cluster集群方式:**
```shell
# redis主节点
docker run --name redis-master1 --net env-net --ip=192.168.146.77 -p=6377:6377 -v /env/redis/config:/redis/config -d redis:7.0.5 redis-server /redis/config/redis-master1.conf
docker run --name redis-master2 --net env-net --ip=192.168.146.78 -p=6378:6378 -v /env/redis/config:/redis/config -d redis:7.0.5 redis-server /redis/config/redis-master2.conf
docker run --name redis-master3 --net env-net --ip=192.168.146.79 -p=6379:6379 -v /env/redis/config:/redis/config -d redis:7.0.5 redis-server /redis/config/redis-master3.conf
# redis从节点
docker run --name redis-salve1 --net env-net --ip=192.168.146.80 -p=6380:6380 -v /env/redis/config:/redis/config -d redis:7.0.5 redis-server /redis/config/redis-salve1.conf
docker run --name redis-salve2 --net env-net --ip=192.168.146.81 -p=6381:6381 -v /env/redis/config:/redis/config -d redis:7.0.5 redis-server /redis/config/redis-salve2.conf
docker run --name redis-salve3 --net env-net --ip=192.168.146.82 -p=6382:6382 -v /env/redis/config:/redis/config -d redis:7.0.5 redis-server /redis/config/redis-salve3.conf
# redis哨兵
docker run --name redis-sentinel --net="host" -p=26379:26379 -v /env/redis/config:/redis/config -d redis:7.0.5 redis-sentinel /redis/config/redis-sentinel.conf
# 自动为所有的redis配置集群通信、自动分配槽、自动主从配置
docker exec -it redis-master1 /bin/bash
redis-cli --cluster create --cluster-replicas 1 -a 123123 192.168.146.77:6377 192.168.146.78:6378 192.168.146.79:6379 192.168.146.80:6380 192.168.146.81:6381 192.168.146.82:6382
#之前启动redis集群,直接启动所有容器即可。所以可以写个脚本来启动
touch redis-cluster-start.sh
#!/bin/bash
sudo systemctl start docker
docker start redis-master1
docker start redis-master2
docker start redis-master3
docker start redis-salve1
docker start redis-salve2
docker start redis-salve3
# 执行脚本
bash redis-cluster-start.sh
```
---
## es+kibana
**扩展知识点:**
1. 不挂载config、data目录,es8会自动生成yml文件,并且会配置用户名和密码,用户名和密码在es日志里,挂载以后就生成不出来config里的所有配置
```shell
# 挂载es配置
/env/es/config:/usr/share/elasticsearch/config
# 挂载配置文件
/env/es/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
# 挂载es数据目录
/env/es/data:/usr/share/elasticsearch/data
# 挂载es的插件目录
/env/es/plugins:/usr/share/elasticsearch/plugins
# 挂载es的日志
/env/es/logs:/usr/share/elasticsearch/logs
```
1. es8默认采用https方式访问
**步骤:**https://www.pudn.com/news/63280781272bb74d44c6c76f.html
1. 下载es镜像
```shell
# es8的集群很难搭建
docker pull elasticsearch:8.4.1
# es7的集群
docker pull elasticsearch:7.17.6
```
2. 启动es镜像。注意:es默认是集群启动
```shell
###############################单机es#########################################
# 自动生成yml、身份认证证书等
# 注意:必须以-it启动第一次,因为密码不会写到日志里去
docker run --name es --net="bridge" -p 9200:9200 -p 9300:9300 \
-e "discovery.type=single-node" \
-e CLI_JAVA_OPTS="-Xms64m -Xmx128m" \
-v /opt/elasticsearch/plugins:/usr/share/elasticsearch/plugins \
-it elasticsearch:8.4.1
# 可以通过下面操作来重置密码
docker exec -it es bash
cd /usr/share/elasticsearch/
bin/elasticsearch-reset-password -u elastic -i
###############################集群es#########################################
```
3. 下载kibana镜像
```shell
docker pull kibana:8.4.1
```
4. 启动kibana镜像
```shell
docker run -d --name kibana --net="host" -p 5601:5601 kibana:8.4.1
```
---
## RabbitMQ
```shell
docker pull rabbitmq:3.11
```
---
## nacos
**扩展知识点:**
如果觉得nacos的配置不满意,则可以挂载 `custom.properties`文件到 `/home/nacos/init.d/`容器目录
```properties
server.port=8850
```
```shell
docker run --name nacos123 -e MODE=standalone -p 8848:8848 -v /env/nacos:/home/nacos/init.d -d nacos/nacos-server:v2.1.1
```
window数据库,默认只能由本地localhos连接,如果希望其他人也可以连接本地数据库,则需要修改mysql库的user表
```sql
use mysql;
update user set host = '%' where user ='root';
flush privileges;
select host,user from user u where u.`user`="root"
```
**步骤:**https://hub.docker.com/r/nacos/nacos-server
1. 下载nacos镜像
```shell
docker pull nacos/nacos-server:v2.1.1
```
2. 启动nacos镜像
```shell
# -e NACOS_AUTH_TOKEN=SecretKey0123456789 \带上这个访问不了
docker run --name nacos -e MODE=standalone -e NACOS_APPLICATION_PORT=8850 --network="host" -p 8850:8850 -d nacos/nacos-server:v2.1.1
##############################||单机nacos||#################################
docker run --name nacos \
-e MODE=standalone -e NACOS_APPLICATION_PORT=8850 \
-e SPRING_DATASOURCE_PLATFORM=mysql -e MYSQL_SERVICE_HOST=192.168.7.161 \
-e MYSQL_SERVICE_DB_NAME=nacos -e MYSQL_SERVICE_USER=root -e MYSQL_SERVICE_PASSWORD=123123 \
-e MYSQL_SERVICE_DB_PARAM="serverTimezone=Asia/Shanghai&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&allowPublicKeyRetrieval=true" \
-e NACOS_AUTH_ENABLE=true -e NACOS_AUTH_TOKEN_EXPIRE_SECONDS=18000 \
--network="host" -p 8850:8850 -d nacos/nacos-server:v2.1.1
##############################||集群nacos||#################################
docker run --name nacos1 \
-e NACOS_SERVERS="192.168.24.246:8848,192.168.24.246:8850,192.168.24.246:8852" -e NACOS_APPLICATION_PORT=8848 \
-e SPRING_DATASOURCE_PLATFORM=mysql -e MYSQL_SERVICE_HOST=192.168.24.246 \
-e MYSQL_SERVICE_DB_NAME=nacos -e MYSQL_SERVICE_USER=root -e MYSQL_SERVICE_PASSWORD=123123 \
-e MYSQL_SERVICE_DB_PARAM="serverTimezone=Asia/Shanghai&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&allowPublicKeyRetrieval=true" \
-e NACOS_AUTH_ENABLE=true -e NACOS_AUTH_TOKEN_EXPIRE_SECONDS=18000 \
--network="host" -p 8848:8848 -d nacos/nacos-server:v2.1.1
docker run --name nacos2 \
-e NACOS_SERVERS="192.168.24.246:8848,192.168.24.246:8850,192.168.24.246:8852" -e NACOS_APPLICATION_PORT=8850 \
-e SPRING_DATASOURCE_PLATFORM=mysql -e MYSQL_SERVICE_HOST=192.168.24.246 \
-e MYSQL_SERVICE_DB_NAME=nacos -e MYSQL_SERVICE_USER=root -e MYSQL_SERVICE_PASSWORD=123123 \
-e MYSQL_SERVICE_DB_PARAM="serverTimezone=Asia/Shanghai&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&allowPublicKeyRetrieval=true" \
-e NACOS_AUTH_ENABLE=true -e NACOS_AUTH_TOKEN_EXPIRE_SECONDS=18000 \
--network="host" -p 8850:8850 -d nacos/nacos-server:v2.1.1
docker run --name nacos3 \
-e NACOS_SERVERS="192.168.24.246:8848,192.168.24.246:8850,192.168.24.246:8852" -e NACOS_APPLICATION_PORT=8852 \
-e SPRING_DATASOURCE_PLATFORM=mysql -e MYSQL_SERVICE_HOST=192.168.24.246 \
-e MYSQL_SERVICE_DB_NAME=nacos -e MYSQL_SERVICE_USER=root -e MYSQL_SERVICE_PASSWORD=123123 \
-e MYSQL_SERVICE_DB_PARAM="serverTimezone=Asia/Shanghai&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&allowPublicKeyRetrieval=true" \
-e NACOS_AUTH_ENABLE=true -e NACOS_AUTH_TOKEN_EXPIRE_SECONDS=18000 \
--network="host" -p 8852:8852 -d nacos/nacos-server:v2.1.1
```
---
## seata
```shell
docker pull seataio/seata-server:1.5.2
```
---
## sentinel
自己打包成镜像
---
# DockerFile
用于构建docker镜像文件
**docker build 【option】 dockerfile文件目录**
>构建docker镜像文件
>
>**参数:**
>
>option
>
>* **-f dockerfile目录下的dockerfile文件名:**指定docker镜像文件脚本文件的文件名
>* **-t 镜像名[:版本号]:**指定即将生成的镜像名和版本号
>
>```shell
>docker build -f dockerfile -t demo:0.0.1 .
>```
**docker login -u 账户名**
>登录dockerhub的账户,后面就可以将镜像发布到dockerhub上了
**docker tag 本地镜像name或者id[:版本号] 新镜像名[:新版本号]**
>将根据本地镜像创建一个新版本的镜像
**docker push 用户名/仓库名:标签名**
>将标签名(镜像名)发布到我的dockerhub上的指定仓库中
>
>```shell
>docker push 2412594046/image_env:redis-cluster
>```
>
>一般在国内会将镜像发布到阿里云的容器服务那边。
>
>步骤:
>
>1. 登录阿里云
>2. 找到容器镜像服务
>3. 创建命名空间
>4. 创建容器仓库
>5. 在根据仓库内的命令指定做
---
## 命令
dockerfile是不区分大小写的,但是我们一般用命令是大写的。
### 基础镜像信息
**FROM 基础镜像**
>从哪个基础镜像的基础上构建我们的镜像。即叠层
### 维护者信息
**MAINTAINER 作者<邮箱>**
>指定该镜像创作者和联系邮箱
### 镜像操作指令
**ENV 键名 值**
>定义一个环境变量,可以通过$变量名获取
>
>也可以在启动容器时通过 `-e 环境变量名=变量值` 来指定环境变量值
>
>```shell
>ENV CATALINA_HOME /usr/local/tomcat
>```
**WORKDIR 目录**
>指定当我们容器启动时,容器的工作目录,即我们进入容器内部时的目录。即命令操作容器内时是在该目录下
**RUN shell命令**
>构建镜像时,执行的命令
**COPY 要拷贝进入容器的文件 拷贝到容器里的哪个目录下**
>将本地的文件拷贝进入到容器的指定目录下。但是不会自动解压压缩文件
>
>```shell
>COPY docker-entrypoint.sh /usr/local/bin/
>```
**ADD 本地文件位置 添加到镜像里的哪个目录下**
>将本地文件添加到镜像的指定目录下。tar类型文件会自动解压
**EXPOSE 端口 ...**
>指定容器要暴露的端口,而不是-p端口映射,所以外网访问得-p进行端口映射,才访问到
### 容器启动执行命令
**CMD shell命令**
>当命令 指定参数时,CMD会被替换,而ENTRYPOINT是追加
>
>比如:
>
>dockerfile脚本文件里
>
>CMD ["ls","-a"]
>
>当构建成镜像后,在进行docker run -l时,会报错,这时因为 ls -a 被替换成了 -l
>
>而ENTRYPOINT,就不会,这时因为 ls -al,在命令尾部追加了该参数
**ENTRYPOINT shell命令**
>当命令 指定参数时,CMD会被替换,而ENTRYPOINT是追加
## 例子
打包springboot程序成镜像
```shell
# 基础的镜像环境:java8运行环境
FROM java:8
# 作者信息
MAINTAINER Hzp<2412594046@qq.com>
# 定义一个环境变量,dockerfile每一行相当于叠加一层
ENV WORK_DIR /hzp/springboot
# 所以这里可以访问到上一层定义的ENV环境变量
ENV JAR_POS $WORK_DIR/demo-0.0.1-SNAPSHOT.jar
# 定义容器开始的工作目录
WORKDIR $WORK_DIR
# 构建镜像时,会将指定的目录或者文件拷贝到容器内部的指定位置上
ADD demo-0.0.1-SNAPSHOT.jar $JAR_POS
# 构建镜像时执行该shell目录,即给jar文件添加可执行权限
RUN chmod +x $JAR_POS
# 暴露端口8080,这个暴露端口是指容器暴露8080端口,而不是端口映射
EXPOSE 8080
# 当docker run是运行该命令
# CMD ["java","-jar", "$JAR_POS"] 不能解析$JAR_POS
CMD java -jar $JAR_POS
docker build -f dockerfile -t demo:0.0.1 .
docker run --name de -p 8080:8080 -it demo:0.0.1
```
---
# Docker Compose
---
# Docker Swarm
---
# CI/CD Jenkins流水线