Docker学习笔记

Docker

简介

概述

打包源码+配置+环境+版本等信息,解决了运行环境和配置问题的软件容器,方便做持续集成并有助于整体发布的容器虚拟化技术。

在这里插入图片描述

Docker和 虚拟机的 区别

虚拟机

将整套Linux操作系统移植到Windows操作系统上

虚拟机的缺点:1 资源占用多 2 冗余步骤多 3 启动慢

Docker

提供的镜像包含了应用的所有依赖项,因而在从开发到测试再到生产的整个过程中,它都具有可移植性和一致性。将软件运行所需的所有资源打包到一个隔离的容器中。容器与虚拟机不同,不需要捆绑一整套操作系统,只需要软件工作所需的库资源和设置。

比较

比较了 Docker 和传统虚拟化方式的不同之处:*传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;*容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。 每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。

基本组成

镜像

Docker 镜像(Image)就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。它也相当于是一个root文件系统。相当于容器的“源代码”,docker镜像文件类似于Java的类模板,而docker容器实例类似于java中new出来的实例对象。

容器

容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。就像是Java中的类和实例对象一样,镜像是静态的定义,容器是镜像运行时的实体。容器为镜像提供了一个标准的和隔离的运行环境,它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台 2 从镜像容器角度可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。

仓库

仓库(Repository)是集中存放镜像文件的场所。 仓库分为公开仓库(Public)和私有仓库(Private)两种形式。最大的公开仓库是 Docker Hub(https://hub.docker.com/),存放了数量庞大的镜像供用户下载。国内的公开仓库包括阿里云 、网易云等

常见命令

帮助启动类命令

  • 启动/停止/重启/状态docker: systemctl start/stop/restart/status docker
  • 开机启动: systemctl enable docker
  • 查看docker概要信息: docker info
  • 查看docker总体帮助文档: docker --help
  • 查看docker命令帮助文档: docker 具体命令 --help

镜像命令

  • 列出本地主机上的镜像: docker images

-a :列出本地所有的镜像(含历史映像层)

-q :只显示镜像ID。

  • 下载镜像: docker search 镜像名

–limit : 只列出N个镜像,默认25个(docker search --limit isoName)

  • 拉取镜像:docker pull 某个XXX镜像名字[:TAG]
  • 查看镜像/容器/数据卷所占的空间: docker system df
  • 删除镜像: docker rmi 某个XXX镜像名字ID

删除多个:docker rmi -f 镜像名1:TAG 镜像名2:TAG

全部删除: docker rmi -f $(docker images -qa)

虚悬镜像

仓库名、标签都是的镜像,构建错误所产生。俗称虚悬镜像dangling image

  • 删除所有的虚悬镜像: docker image prune

容器命令

  • 新建/启动容器: docker run [OPTIONS] IMAGE [COMMAND] [ARG…]

–name=“容器新名字” 为容器指定一个名称;

-d: 后台运行容器并返回容器ID,也即启动守护式容器(后台运行);

-i:以交互模式运行容器,通常与 -t 同时使用;

-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用;也即启动交互式容器(前台有伪终端,等待交互);

-P: 随机端口映射

-p: 指定端口映射(格式:-p 主机端口:容器端口)

-d: 后台启动

–restart=always 虚拟机重启该容器也会重启

#使用镜像centos:latest以后台模式启动一个容器docker run -d centos 问题:然后docker ps -a 进行查看, 会发现容器已经退出很重要的要说明的一点: Docker容器后台运行,就必须有一个前台进程.容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail),就是会自动退出的。

docker run -d ubuntu 启动的容器因为没有持续运行的进程,会立即停止,所以在docker ps中看不到。

docker run -d redis 启动的容器中有一个持续运行的 Redis 服务进程,容器会持续运行,所以在docker ps中可以看到。

example

#使用镜像centos:latest以交互模式启动一个容器,在容器内执行/bin/bash命令。

docker run -it centos /bin/bash 

参数说明:-i: 交互式操作。-t: 终端。centos : centos 镜像。/bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。要退出终端,直接输入 exit: 
  • 列出当前运行的容器:docker ps [OPTIONS]

-a :列出当前所有正在运行的容器+历史上运行过的

-n 参数: 列出前n个容器(停止非停止都会列出)

-l :显示最近创建的容器。

-n:显示最近n个创建的容器。

-q :静默模式,只显示容器编号。

  • 退出容器:

exit run进去容器,exit退出,容器停止

ctrl+p+q run进去容器,ctrl+p+q退出,容器不停止

  • 启动已停止运行的容器: docker start 容器ID或者容器名
  • 重启/停止容器: docker restart/stop 容器ID或者容器名
  • 强制停止容器: docker kill 容器ID或容器名
  • 删除已停止的容器: docker rm 容器ID

若在运行,可添加-f强制删除

  • 一次性 删除所有容器示例

docker rm -f $(docker ps -a -q)

  • 批量删除已停止的容器

docker ps -a -q | xargs docker rm

  • 查看容器日志: docker logs 容器ID

  • 查看容器内运行的进程: docker top 容器ID

  • 查看容器内部细节: docker inspect 容器ID

  • 进入正在运行的容器并以命令行交互

    • docker attach 容器id (attach 直接进入容器启动命令的终端,不会启动新的进程
      用exit退出,会导致容器的停止。)
    • docker exec -it 容器ID bashShell (exec 是在容器中打开新的终端,并且可以启动新的进程
      用exit退出,不会导致容器的停止。)
  • 将容器内的文件拷贝到当前主机: docker cp 容器ID:容器内路径 目的主机路径

  • 导出容器的内容留作为一个tar归档文件到当前主机目录下:docker export 容器ID > 文件名.tar

  • 从tar包中的内容创建一个新的文件系统再导入为镜像: cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号

其他容器常见命令
图片正下方还有命令 attach    Attach to a running container         
# 当前 shell 下 attach 连接指定运行镜像build     Build an image from a Dockerfile          # 通过 Dockerfile 定制镜像commit    Create a new image from a container changes  
# 提交当前容器为新的镜像cp        Copy files/folders from the containers filesystem to the host path  
#从容器中拷贝指定文件或者目录到宿主机中create    Create a new container                      # 创建一个新的容器,同 run,但不启动容器diff      Inspect changes on a container's filesystem   
# 查看 docker 容器变化events    Get real time events from the server        
# 从 docker 服务获取容器实时事件exec      Run a command in an existing container        
# 在已存在的容器上运行命令export    Stream the contents of a container as a tar archive   # 导出容器的内容流作为一个 tar 归档文件[对应 import ]history   Show the history of an image  # 展示一个镜像形成历史images    List images                                
# 列出系统当前镜像import    Create a new filesystem image from the contents of a tarball # 从tar包中的内容创建一个新的文件系统映像[对应export]info      Display system-wide information              
# 显示系统相关信息inspect   Return low-level information on a container   
# 查看容器详细信息kill      Kill a running container                      
# kill 指定 docker 容器load      Load an image from a tar archive              
# 从一个 tar 包中加载一个镜像[对应 save]login     Register or Login to the docker registry server    
# 注册或者登陆一个 docker 源服务器logout    Log out from a Docker registry server          # 从当前 Docker registry 退出logs      Fetch the logs of a container                 
# 输出当前容器日志信息port      Lookup the public-facing port which is NAT-ed to PRIVATE_PORT    
# 查看映射端口对应的容器内部源端口pause     Pause all processes within a container        
# 暂停容器ps        List containers                               
# 列出容器列表pull      Pull an image or a repository from the docker registry server   # 从docker镜像源服务器拉取指定镜像或者库镜像push      Push an image or a repository to the docker registry server    
# 推送指定镜像或者库镜像至docker源服务器restart   Restart a running container                # 重启运行的容器rm        Remove one or more containers                 
# 移除一个或者多个容器rmi       Remove one or more images       
# 移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或 -f 强制删除]run       Run a command in a new container              
# 创建一个新的容器并运行一个命令save      Save an image to a tar archive                
# 保存一个镜像为一个 tar 包[对应 load]search    Search for an image on the Docker Hub      # 在 docker hub 中搜索镜像start     Start a stopped containers                   
# 启动容器stop      Stop a running containers                    
# 停止容器tag       Tag an image into a repository                
# 给源中镜像打标签top       Lookup the running processes of a container   
# 查看容器中运行的进程信息unpause   Unpause a paused container                    
# 取消暂停容器version   Show the docker version information           
# 查看 docker 版本号wait      Block until a container stops, then print its exit code   # 截取容器停止时的退出状态值 

Docker镜像

commit

commit提交容器副本使之成为一个新的镜像,复用原镜像的基础内容

  • docker commit -m=“提交的描述信息” -a=“作者” 容器ID 要创建的目标镜像名:[标签名]

Docker容器数据卷(必须加–privileged=true)

将docker容器内的数据保存进宿主机的磁盘中,运行一个带有容器卷存储功能的容器实例,有点类似我们Redis里面的rdb和aof文件

特点:1:数据卷可在容器之间共享或重用数据2:卷中的更改可以直接实时生效,爽3:数据卷中的更改不会包含在镜像的更新中4:数据卷的生命周期一直持续到没有容器使用它为止

  • docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名

容器卷和主机互联

互联后,宿主机目录下和容器内目录下的文件双向同步,即使docker关闭了,也会在下一次重启docker时同步信息

以下读写都是对容器进行限制

直接命令添加(默认读写)
  • docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名

:rw 读写

:ro 只读

ps: 没有标注的话默认为读写(-v /宿主机绝对路径目录:/容器内目录:rw)

卷的继承和共享

  • docker run -it --privileged=true --volumes-from 父类名 --name 名字 镜像名

实现继承后,子类和父类一样会和主机互联。

如果父类宕机了,子类依旧和主机互联。

如果父类宕机恢复,在宕机这段时间子类和主机互联的数据在父类依然存在。

基本软件安装

tomcat

注意: 最新版Tomcat需要把webapps删除,将webapps.dist重命名为webapps

mysql

需要添加容器卷,解决乱码,备份等问题,

docker run -d -p 3306:3306 --privileged=true 
-v /cqx/mysql/log:/var/log/mysql 
-v /cqx/mysql/data:/var/lib/mysql 
-v /cqx/mysql/conf:/etc/mysql/conf.d 
-v /cqx/mysql/mysql-files:/var/lib/mysql-files
-e MYSQL_ROOT_PASSWORD=123456  --name mysql
mysql:5.7

注意要加入mysql-files,MySQL服务器配置了--secure-file-priv参数用于限制可以从哪个目录导入/导出文件。默认情况下,MySQL服务器设置了--secure-file-priv参数指向/var/lib/mysql-files/目录,这个目录是MySQL服务器可以读写的目录。

方法1: 新建一个mysql-files目录用于存储文件

-v /cqx/mysql/mysql-files:/var/lib/mysql-files

方法2: 宿主机自定义mysql配置文件my.cnf,并将自定义的配置文件挂载到容器中的MySQL配置目录

redis

现在主机修改配置文件,指定redis配置

 docker run  -p 6379:6379 --name myr3 --privileged=true 
 -v /app/redis/redis.conf:/etc/redis/redis.conf 
 -v /app/redis/data:/data -d 
 redis:6.0.8 redis-server /etc/redis/redis.conf   

1~2亿条数据需要缓存,请问如何设计这个存储

方案1:哈希取余分区

直接用hash(key) % N个机器台数

简单粗暴,但是原来规划好的节点,进行扩容或者缩容就比较麻烦

方案2: 一致性哈希算法分区
构建一致性哈希环

对2^32取模,简单来说,一致性Hash算法将整个哈希值空间组织成一个虚拟的圆环

在这里插入图片描述

服务器ip节点映射

通过ip地址的哈希函数计算服务器在哈希环上的位置

在这里插入图片描述

key落到服务器的落键

当我们需要存储一个kv键值对时,首先计算key的hash值,hash(key),将这个key使用相同的函数Hash计算出哈希值并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器,并将该键值对存储在该节点上。如我们有Object A、Object B、Object C、Object D四个数据对象,经过哈希计算后,在环空间上的位置如下:根据一致性Hash算法,数据A会被定为到Node A上,B被定为到Node B上,C被定为到Node C上,D被定为到Node D上。

在这里插入图片描述

方案3: 哈希槽

edis 集群中内置了 16384 个哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。当需要在 Redis 集群中放置一个 key-value时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,也就是映射到某个节点上。如下代码,key之A 、B在Node2, key之C落在Node3上

slot = CRC16(key) % 16384。

mysql主从配置

新建主机实例
docker run -p 3307:3306 --name mysql-master \-v /mydata/mysql-master/log:/var/log/mysql \-v /mydata/mysql-master/data:/var/lib/mysql \-v /mydata/mysql-master/conf:/etc/mysql \-e MYSQL_ROOT_PASSWORD=root  \-d mysql:5.7
新建主机配置文件
[mysqld]## 设置server_id,同一局域网中需要唯一server_id=101 ## 指定不需要同步的数据库名称binlog-ignore-db=mysql  ## 开启二进制日志功能log-bin=mall-mysql-bin  ## 设置二进制日志使用内存大小(事务)binlog_cache_size=1M  ## 设置使用的二进制日志格式(mixed,statement,row)binlog_format=mixed  ## 二进制日志过期清理时间。默认值为0,表示不自动清理。expire_logs_days=7  ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致slave_skip_errors=1062
主机容器实例内创建数据同步用户
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
新建从机实例
docker run -p 3308:3306 --name mysql-slave \-v /mydata/mysql-slave/log:/var/log/mysql \-v /mydata/mysql-slave/data:/var/lib/mysql \-v /mydata/mysql-slave/conf:/etc/mysql \-e MYSQL_ROOT_PASSWORD=root  \-d mysql:5.7

新建从机配置文件
[mysqld]## 设置server_id,同一局域网中需要唯一server_id=102## 指定不需要同步的数据库名称binlog-ignore-db=mysql  ## 开启二进制日志功能,以备Slave作为其它数据库实例的Master时使用log-bin=mall-mysql-slave1-bin  ## 设置二进制日志使用内存大小(事务)binlog_cache_size=1M  ## 设置使用的二进制日志格式(mixed,statement,row)binlog_format=mixed  ## 二进制日志过期清理时间。默认值为0,表示不自动清理。expire_logs_days=7  ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致slave_skip_errors=1062  ## relay_log配置中继日志relay_log=mall-mysql-relay-bin  ## log_slave_updates表示slave将复制事件写进自己的二进制日志log_slave_updates=1  ## slave设置为只读(具有super权限的用户除外)read_only=1

  • 在主数据库中查看主从同步状态: show master status;
主机容器实例内创建数据同步用户
change master to master_host='宿主机ip', master_user='slave', master_password='123456', master_port=3307, master_log_file='mall-mysql-bin.000001', master_log_pos=617, master_connect_retry=30;  

master_host:主数据库的IP地址;master_port:主数据库的运行端口;master_user:在主数据库创建的用于同步数据的用户账号;master_password:在主数据库创建的用于同步数据的用户密码;master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数;master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position参数;master_connect_retry:连接失败重试的时间间隔,单位为秒。 

在从数据库中查看主从同步状态
show slave status \G;

从数据库容器实例中开启主从同步
start slave

3主3从redis配置

新建六台redis容器实例

docker run -d --name redis-node-1 --net host --privileged=true -v /data/redis/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381 
docker run -d --name redis-node-2 --net host --privileged=true -v /data/redis/share/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382 
docker run -d --name redis-node-3 --net host --privileged=true -v /data/redis/share/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383 
docker run -d --name redis-node-4 --net host --privileged=true -v /data/redis/share/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384 
docker run -d --name redis-node-5 --net host --privileged=true -v /data/redis/share/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385 
docker run -d --name redis-node-6 --net host --privileged=true -v /data/redis/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386

随便进入一台容器,配置主从关系

redis-cli --cluster create 192.168.100.149:6381 192.168.100.149:6382 192.168.100.149:6383 192.168.100.149:6384 192.168.100.149:6385 192.168.100.149:6386 --cluster-replicas 1 

// --cluster-replicas 1 表示为每个master创建一个slave节点   ip地址填linux主机地址


  • 查看集群信息: cluster info
  • 查看集群状态: cluster nodes

ps: 由于使用插槽机制,会为每个key使用Crc算法计算出特定值,将特定key放到特定槽上。如果以单机形式启动redis容器,可能会有某些key所对应的Crc值不属于这台redis容器的槽。

也就是需要以集群方式启动redis容器,在命令后加入参数-c

例:redis-cli -p 6381 -c

  • 查看集群信息: redis-cli --cluster check ip:集群内中任一端口

在前面的redis 3主3从前提下 进行扩容(添加主6387 从6388)

新建主6387和从6388两个节点
docker run -d --name redis-node-7 --net host --privileged=true -v /data/redis/share/redis-node-7:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6387docker run -d --name redis-node-8 --net host --privileged=true -v /data/redis/share/redis-node-8:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388docker ps 

将主机加入到集群(未分配槽)
 将新增的6387作为master节点加入集群
 redis-cli --cluster add-node 自己实际IP地址:6387 自己实际IP地址:63816387 
 就是将要作为master新增节点6381 就是原来集群节点里面的领路人,相当于6387拜拜6381的码头从而找到组织加入集群 

为6387主机分配槽
重新分派槽号命令:
redis-cli --cluster reshard IP地址:端口号

需要给该主机移动多少单位的槽

在这里插入图片描述

接收分配槽的主机id是什么

在这里插入图片描述

分配方式:

all 每个主机均匀分配一部分给该主机

done 输入要匀出槽位的主机的id

在这里插入图片描述

将从机6388设为主机6387的从节点
命令:
redis-cli --cluster add-node ip:新slave端口 ip:新master端口 --cluster-slave --cluster-master-id 新主机节点ID 

在前面的redis 4主4从前提下 进行缩容(删除主6387 从6388)

先删除从机6388

因为从机为读操作,先删主机可能部分写操作会丢失

 命令:
 redis-cli --cluster del-node ip:从机端口 从机6388节点ID 

清除主机槽位
redis-cli --cluster reshard 192.168.111.147:6381  

在这里插入图片描述

删除主机6388
 命令:redis-cli --cluster del-node ip:端口 6387节点ID 

DockerFile

Dockerfile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。

DockerFile,镜像,容器三者之间的关系

在这里插入图片描述

构建步骤

  • 编写DockerFile文件
  • dokcer build命令构建镜像
  • docker run允许镜像实例

Dockerfile内容基础知识

1:每条保留字指令都必须为大写字母且后面要跟随至少一个参数

2:指令按照从上到下,顺序执行

3:#表示注释

4:每条指令都会创建一个新的镜像层并对镜像进行提交

DockerFile常用保留字指令

FROM

基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from

MAINTAINER

镜像维护者的姓名和邮箱地址

RUN

容器构建时需要运行的命令,RUN是在 docker build 构建(DockerFile -> 镜像)时运行

格式1: shell
RUN <命令行命令>
命令行命令等同于在终端的shell命令
例: 
RUN yum -y install vim

格式2:exec
RUN [“可执行文件”,“para1”,“para2”]
例: RUN [“./a.php”,“dev”,“offline”] 等价于 RUN ./a.php dev offline
RUN yum -y install vim  等价于 RUN ["yum", "-y", "install", "vim"]

EXPOSE

当前容器对外暴露出的端口

WORKDIR

指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点

USER

指定该镜像以什么样的用户去执行,如果都不指定,默认是root

ENV

用来在构建镜像过程中设置环境变量

例:
设置环境变量
ENV MY_PATH /usr/mytest
使用环境变量
WORKDIR $MY_PATH

COPY

拷贝宿主机的文件和目录到镜像中。
将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置

写法1:COPY src dest
写法2:COPY ["src", "dest"]
<src源路径>:源文件或者源目录
<dest目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。

ADD

将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包,可视为有解压功能的COPY

ADD 文件 文件在容器实例的路径/文件名

VOLUME

容器数据卷,用于数据保存和持久化工作

VOLUME /PATH


VOLUME /data
容器的/data会和宿主机的/host/data同步,也就是/host/PATH所写的地址

CMD

指定容器启动后的要干的事情,CMD是在docker run 时运行。

Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换

CMD[“<para1>”,"<para2>"]
例:
CMD ["nginx", "-g", "daemon off;"]
在linux终端对应的命令
nginx -g "daemon off;"

CMD ["java", "-jar", "myapp.jar"]
在linux终端对应的命令
java -jar myapp.jar

如果在docker run上加入相关参数的话,CMD的内容会被docker run的参数覆盖

tomcat最后一个CMD是 "CMD["catalina.sh",run]"
输入启动命令: docker run -it -p 8080:8080 tomcat /bin/bash
因为加入了/bin/bash操作,可视为加了CMD["/bin/bash","run"]
此时运行localhost:8080,无法正常访问

ENTRYPOINT

也是用来指定一个容器启动时要运行的命令,类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序

格式:
ENTRYPOINT ["<exec>","<para1>","<para2>"]

ENTRYPOINT可以和CMD一起用,一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参。当指定了ENTRYPOINT后,CMD的含义就发生了变化,不再是直接运行其命令而是将CMD的内容作为参数传递给ENTRYPOINT指令,他两个组合会变成

假设有nginx:test镜像

ENTRYPOINT ["nginx","-c"] # 定参
CMD ["/nginx/nginx.conf"]# 变参

对应到linux终端则是
nginx -c /nginx/nginx.conf

但如果在命令上传入了和ENTRYPOINT的相关操作,则会覆盖ENTRYPOINT

例:
docker run -it nginx:test .etc/nginx/my.conf

对应到linux终端则是
nginx -c /nginx/my.conf

自定义ubuntu镜像

创建Dockerfile文件

注意名字必须是Dockerfile

FROM ubuntu
MAINTAINER cqx<mnixqc@163.com> 
ENV MYPATH /usr/local
WORKDIR $MYPATH 
RUN apt-get update
RUN apt-get -y install vim
RUN apt-get install net-tools
RUN apt-get install -y iproute2
RUN apt-get install -y inetutils-ping 
EXPOSE 80 
CMD echo $MYPATH
CMD echo "install inconfig cmd into ubuntu success--------------ok"
CMD /bin/bash 


构建Dockerfile
  • docker build -t 新镜像名字:TAG .

例:docker build -t myubuntu:777 .

运行镜像容器
  • docker run -it 新镜像名字:TAG

Docker微服务实战案例

1.用maven将项目打包成.jar文件发送到linux
2.编写Dockerfile
例:
# 基础镜像使用java
FROM java:8
# 作者
MAINTAINER zzyy
# VOLUME 指定临时文件目录为/tmp,在主机/var/lib/docker目录下创建了一个临时文件并链接到容器的/tmp
VOLUME /tmp
# 将jar包添加到容器中并更名为zzyy_docker.jar
ADD docker_boot-0.0.1-SNAPSHOT.jar zzyy_docker.jar
#在容器中执行命令,创建一个空文件 /zzyy_docker.jar  运行jar包
RUN bash -c 'touch /zzyy_docker.jar'
ENTRYPOINT ["java","-jar","/zzyy_docker.jar"]
#暴露6001端口作为微服务
EXPOSE 6001 

3.构建镜像
4.运行容器并测试

Dokcer网络

docker启动后,会产生一个名为docker0的虚拟网桥,用于宿主机和各个容器内的通信

docker容器内部的ip是有可能会发生改变的,所以需要配置网络服务

虚拟网桥 docker0 是 Docker 在安装时创建的一个默认的网络桥接口,它具有以下作用:

连接 Docker 容器和宿主机网络:docker0 充当了 Docker 容器和宿主机之间的网桥,使得容器可以与宿主机进行通信。当 Docker 容器启动时,它们会连接到 docker0 网桥,从而实现容器和宿主机之间的网络通信。

为容器分配 IP 地址:docker0 网桥会为连接到它上的容器分配 IP 地址。Docker 在启动容器时,会自动为容器分配一个 IP 地址,这个 IP 地址是在 docker0 网桥的子网范围内的。

实现容器间通信:通过 docker0 网桥,不同容器之间也可以进行网络通信。Docker 在创建容器时会为每个容器分配一个虚拟网卡,并将这些虚拟网卡连接到 docker0 网桥上,从而实现容器间的通信。

连接到外部网络:docker0 网桥还允许 Docker 容器访问宿主机所在的网络以及外部网络,实现容器与外部世界的通信。

在这里插入图片描述

Docker网络命令

  • 查看命令使用方法: docker network --help
  • 查看网络: docker network ls
  • 查看网络数据源: docker network inspect XXX网络名字
  • 删除网络: docker network rm XXX网络名字

Docker网络作用

容器间的互联和通信以及端口映射

容器IP变动时候可以通过p服务名直接网络通信而不受到影响

Docker网络模式

bridge模式:使用–network bridge指定,默认使用docker0

host模式:使用–network host指定

none模式:使用–network none指定

container模式:使用–network container:NAME或者容器ID指定

在这里插入图片描述
在这里插入图片描述

bridge

Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。 # 查看 bridge 网络的详细信息,并通过 grep 获取名称项docker network inspect bridge | grep name ifconfig

1 Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。 2 docker run 的时候,没有指定network的话默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig,就可以看到docker0和自己create的network(后面讲)eth0,eth1,eth2……代表网卡一,网卡二,网卡三……,lo代表127.0.0.1,即localhost,inet addr用来表示网卡的IP地址 3 网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配

3.1 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);   
3.2 每个容器实例内部也有一块网卡,每个接口叫eth0;   
3.3 docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。 通过上述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络是互通的。

在这里插入图片描述

两两匹配验证

在这里插入图片描述

host

直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。无需宿主机和容器端口映射(无意义)

启动加: --network host

在这里插入图片描述

none

禁用网络功能,只有lo标识(就是127.0.0.1表示本地回环)

启动加: --network none

container

container⽹络模式 新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。

启动加: --network container:容器标识

alpine2共享alpine1的网络配置

docker run -it --name alpine1  alpine /bin/sh

docker run -it --network container:alpine1 --name alpine2  alpine /bin/sh

在这里插入图片描述

此时关闭alpine1

在这里插入图片描述

自定义网络模式

自定义网络本身就维护好了主机名和ip的对应关系(ip和域名都能通)

bridege存在的问题:

docker容器内部的ip是有可能会发生改变的,如果ip变动会造成无法连通的问题。

使用bridge模式容器间用ip可以ping通,但通过服务名不能ping通

  • 创建新的网络模式: docker network create networkname
例:
docker run -d -p 8081:8080 --network zzyy_network  --name tomcat81 billygoo/tomcat8-jdk8

docker run -d -p 8082:8080 --network zzyy_network  --name tomcat82 billygoo/tomcat8-jdk8

此时无论ip还是服务名都能互相ping通

Docker-compose容器编排

Docker-Compose是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。

Compose允许用户通过一个单独的docker-compose.yml模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。 可以很容易地用一个配置文件定义一个多容器的应用,然后使用一条指令安装这个应用的所有依赖,完成构建。Docker-Compose 解决了容器与容器之间如何管理编排的问题。

常见Docker Compose命令

Compose常用命令:
  - docker compose -h                           # 查看帮助
  - docker compose up                           # 启动所有docker compose服务
  - docker compose up -d                        # 启动所有docker compose服务并后台运行
  - docker compose down                         # 停止并删除容器、网络、卷、镜像
  - docker compose exec <service_id>            # 进入容器实例内部
  - docker compose exec <service_id> /bin/bash  # 进入容器实例内部执行命令
  - docker compose ps                           # 展示当前docker compose编排过的所有容器
  - docker compose top                          # 展示当前docker compose编排过的容器进程
  - docker compose logs <service_id>            # 查看容器输出日志
  - docker compose config                       # 检查配置
  - docker compose config -q                    # 检查配置,有问题才有输出
  - docker compose restart                      # 重启服务
  - docker compose start                        # 启动服务
  - docker compose stop                         # 停止服务


1.编写docker-compose.yml文件

由于配置了自定义网络模式,所以微服务项目中不用写死mysql,redis的ip。可通过服务名:端口方式访问

version: "3"
services:
  microService:
    image: zzyy_docker:1.6
    container_name: ms01
    ports:
      - "6001:6001"
    volumes:
      - /app/microService:/data
    networks:
      - atguigu_net
    depends_on:
      - redis
      - mysql
# 相当于 docker run -d --name ms01 -p 6001:6001 -v /app/microService:/data --network=atguigu_net --depends-on redis --depends-on mysql zzyy_docker:1.6


  redis:
    image: redis:6.0.8
    ports:
      - "6379:6379"
    volumes:
      - /app/redis/redis.conf:/etc/redis/redis.conf
      - /app/redis/data:/data
    networks:
      - atguigu_net
    command: redis-server /etc/redis/redis.conf
    
# 相当于 docker run -d --name redis -p 6379:6379 -v /app/redis/redis.conf:/etc/redis/redis.conf -v /app/redis/data:/data --network=atguigu_net redis:6.0.8 redis-server /etc/redis/redis.conf


  mysql:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: '123456'
      MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
      MYSQL_DATABASE: 'db2021'
      MYSQL_USER: 'zzyy'
      MYSQL_PASSWORD: 'zzyy123'
    ports:
      - "3306:3306"
    volumes:
      - /app/mysql/db:/var/lib/mysql
      - /app/mysql/conf/my.cnf:/etc/my.cnf
      - /app/mysql/init:/docker-entrypoint-initdb.d
    networks:
      - atguigu_net
    command: --default-authentication-plugin=mysql_native_password #解决外部无法访问

# 相当于: docker run -d --name mysql -e MYSQL_ROOT_PASSWORD='123456' -e MYSQL_ALLOW_EMPTY_PASSWORD='no' -e MYSQL_DATABASE='db2021' -e MYSQL_USER='zzyy' -e MYSQL_PASSWORD='zzyy123' -p 3306:3306 -v /app/mysql/db:/var/lib/mysql -v /app/mysql/conf/my.cnf:/etc/my.cnf -v /app/mysql/init:/docker-entrypoint-initdb.d --network=atguigu_net mysql:5.7 --default-authentication-plugin=mysql_native_password


networks:
  atguigu_net:


指定启动顺序

用depend_on 指定,指定的服务会比当前服务先启动

version: '3.8'

services:
  db:
    image: mysql
    restart: always

  backend:
    image: backend_image
    depends_on:
      - db
    restart: always

  frontend:
    image: frontend_image
    depends_on:
      - backend
    restart: always

在上面的示例中,db 服务会在 backend 服务之前启动,而 backend 服务会在 frontend 服务之前启动。这样,当您使用 docker-compose up 启动这些服务时,Docker Compose 将会按照正确的顺序启动它们。

2.检查并启动容器

  • 检查docker compose文件: - docker compose config -q
  • 启动所有docker compose服务并后台运行 :docker compose up -d

上面docker compose例子启动其中微服务microservice指定了容器名字ms01

在这里插入图片描述

3.停止容器

  • 停止服务: docker compose stop

Portainer

Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。

安装

 docker run -d -p 8000:8000 -p 9000:9000 --name portainer     --restart=always     -v /var/run/docker.sock:/var/run/docker.sock     -v portainer_data:/data     portainer/portainer 

–restart

具体来说,--restart=always参数告诉Docker引擎,无论在何种情况下,只要Docker守护进程在运行,都会自动重启指定的容器。这意味着,如果容器意外终止或Docker引擎重启,Docker将自动重新启动该容器。

访问

第一次登录需创建admin,访问地址:ip:9000

  • 10
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值