民工哥

民工哥 查看完整档案

其它编辑  |  填写毕业院校不知名互联网企业  |  不知名程序员 编辑 github.com/mingongge 编辑
编辑

10多年IT职场老司机的经验分享,坚持自学一路从技术小白成长为互联网企业信息技术部门的负责人。

我的新书:《Linux系统运维指南》

微信公众号:民工哥技术之路

民工哥:知乎专栏

欢迎关注,我们一同交流,相互学习,共同成长!!

个人动态

民工哥 发布了文章 · 4月16日

墙裂推荐!看完全面掌握,最详细的 Docker 学习笔记总结(2021最新版)

Docker 是什么?

Docker 是一个开源的容器引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者和系统管理员在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括 VMs(虚拟机)、bare metal、OpenStack 集群、云端、数据中心和其他的基础应用平台。容器是完全使用沙箱机制,相互之间不会有任何接口。

为啥要用Docker?

为啥要用Docker?这要从目前软件行业的痛点来讲起

  • 1、软件更新发布及部署低效,过程繁琐且需要人工介入
  • 2、环境一致性难以保证
  • 3、不同环境之间迁移成本太高

有了Docker可以很大程度解决上面的问题。

首先,Docker的使用简单至极,从开发的角度来看就是三步走:构建,运输,运行。其中关键步骤就是构建环节,即打包镜像文件。但是从测试和运维的角度来看,那就只有两步:复制,运行。有了这个镜像,那么想复制到哪运行都可以,完全和平台无关了。同时Docker这种容器技术隔离出了独立的运行空间,不会和其他应用争用系统资源了以及还不需要考虑应用之间相互影响,想想就开心。

其次,因为在构建镜像的时候就处理完了服务程序对于系统的所有依赖,所以在你使用的时候,你可以忽略掉原本程序的依赖以及开发语言。对测试和运维而言,更多专注于自己的业务内容上。

最后,Docker于开发者而言提供了一种开发环境的管理办法,与测试人员而言保证了环境的同步,于运维人员提供了可移植的标准化部署流程。

Docker 能干啥?

  • 构建容易分发简单
  • 隔离应用解除依赖
  • 快速部署测完就销

Docker的应用场景在哪??

  1. 本地依赖(Local Dependency)

你需要在本地系统快速尝试 Magento,或者为一个项目使用 MySQL?还是希望尝试大部分开源项目?那就使用 Docker 吧,它将帮你节省大量时间。Docker 能提升开发者的开发效率,让我们快速搭建开发环境。

开发环境的机器通常内存比较小,此前使用虚拟的时候,经常需要为开发环境的机器加内存,而通过 Docker 可以轻易的让几十个服务在 Docker 中跑起来。

  1. 搭建环境(Build Environment)

如果你希望构建源码,但发现没有准备好合适的环境。

那么使用 Docker是一个值得考虑的方案。毕竟如果使用传统的方法一个一个地安装软件,一大堆软件安装下来确实十分费时间,使用容器技术省时省力,何乐而不为?它能让你将运行环境和配置放在代码中然后部署,同一个 Docker 的配置可以在不同的环境中使用,这样就降低了硬件要求和应用环境之间耦合度。这里有一个值得一看的例子: docker golang builder。

  1. 微服务(Microservices)

你在使用微服务吗?微服务架构将一个整体式的应用拆分成松耦合的单个服务。

那不妨考虑一下 Docker,你可以将每个服务打包为一个docker镜像并使用docker-compose 来模拟生产环境(checkout docker networks)。最开始实践的时候可能会比较费时费力,但长远地来看,最终将产生巨大的生产力。

  1. 自动测试(Automated testing)

试想这样一个问题,如何编写自动化的集成测试用例,这些测试用例无需花很长时间来开始运行,使用者也可轻松管理。这里不是指在 Docker 中运行测试用例,而是将测试用例与镜像紧密运行在一起。当你针对一个 docker 镜像编写测试用例时会有一个很大的优势。下面简单介绍一下我的测试流程:运行两个 docker 镜像(app + db),在 MySQL 启动时加载数据,并在 app docker 上使用 API。可查看此脚本以获取快速的示例。

  1. 部署过程(Deployment process)

你可以使用 docker 镜像进行自我部署。许多主流的主机提供商都支持托管 docker,如果你拥有一个具有 shell 访问权限的专用节点/vm,那么事情将变得更容易。只需要设置好docker,并在你想要的端口上运行你的镜像即可。

  1. 持续部署(Continuous Deployment)

都说 Docker 天生适合持续集成/持续部署,在部署中使用Docker,持续部署将变得非常简单,并会在进入新的镜像后重新开始。关于这个部分的自动化工作,现在已经有许多方案以供选择,Kubernetes就是一个耳熟能详的名字。Kubernetes是容器集群管理系统,是一个开源的平台,可以实现容器集群的自动化部署、自动扩缩容、维护等功能。

  1. 多租户环境(Multi-tenancy)

Docker 有意思的一个使用场景是在多租户的应用中,它可以避免关键应用的重写。如果你将应用程序服务公开给多个租户(租户指一组用户,例如组织),使用单租户方案设计的应用程序如果用上了 sub-domain + docker 可以快速获得提供多租户的服务。
关于这个场景的一个例子是为物联网的应用开发一个快速、易用的多租户环境。这种多租户的基本代码非常复杂,很难处理,重新规划这样一个应用不但消耗时间,也浪费金钱。使用Docker,可以为每一个租户的应用层的多个实例创建隔离的环境,这不仅简单而且成本低廉,当然这一切得益于 Docker 环境的启动速度和其高效的 diff 命令。

  1. 来自一台机器的多个 APP(Multiple apps from one machine)

这与上面提到的微服务有些联系,但即使你没有使用微服务,只是提供服务,Docker仍可以很好地管理单个机器上的所有服务。你应该使用文件夹挂载来为每个基于数据的 docker 镜像保留数据。

  1. 扩容 QPS(Scaling QPS)

Docker 通过创建另一个容器来帮助你轻松地进行水平扩展。如果遇到巨大的高峰流量,Docker可以帮助你解决问题 —— 只需添加更多的机器并增加负载均衡器背后运行的容器数量。

想全面了解的朋友可以参考:太全了|万字详解Docker架构原理、功能及使用

Docker与Openstack对比

Docker 生态概览

Docker安装

root@centos7 ~]# yum install docker -y
[root@centos7 ~]# systemctl start docker

下载镜像文件

[root@centos7 ~]# docker pull centos:latest
Trying to pull repository docker.io/library/centos ... 
centos7: Pulling from docker.io/library/centos
93857f76ae30: Pull complete 
Digest: sha256:4eda692c08e0a065ae91d74e82fff4af3da307b4341ad61fa61771cc4659af60
[root@centos7 ~]# docker images
REPOSITORY        TAG      IMAGE ID     CREATED     SIZE
docker.io/centos  centos7  a8493f5f50ff 3 days ago  192.5 MB

删除镜像

[root@centos7 ~]# docker rmi a8493f5f50ff    ##容器ID

Docker容器创建与管理

1)创建容器

方法一:

[root@centos7 ~]# docker run centos /bin/echo "nihao"  ##创建容器
nihao
[root@centos7 ~]# docker ps -a   ##查看所有容器
CONTAINER ID  IMAGE  COMMAND   CREATED    STATUS   PORTS    NAMES
3c113f9a4f1b centos "/bin/echo nihao" 43 seconds ago Exited (0) 41 seconds ago  boring_liskov

这里没有指定容器名称,自动命名,状态是自动退出

方法二:创建一个自定义名称的容器

[root@centos7 ~]# docker run --name mgg -t -i centos /bin/bash
                              名称  分配伪终端  -i 处于打开状态
[root@2db7f1389dbd /]# ps -ef
UID   PID  PPID  C STIME TTY  TIME CMD
root   1    0  0 22:46 ?   00:00:00 /bin/bash
root   13   1  0 22:49 ?  00:00:00 ps -ef
[root@centos7 ~]# docker ps
CONTAINER ID  IMAGE   COMMAND   CREATED   STATUS  PORTS    NAMES
2db7f1389dbd  centos  "/bin/bash"  4 minutes ago   Up 4 minutes   mgg

docker ps -a是显示所有容器包括没有运行的(同virsh list --all)

2)进入、退出、启动容器

[root@2db7f1389dbd /]# exit   ##退出容器
exit
[root@centos7 ~]# docker start 2db7f1389dbd   ##启动容器
2db7f1389dbd
[root@centos7 ~]# docker attach 2db7f1389dbd  ##进入容器(必须是启动状态下)
[root@2db7f1389dbd /]# hostname
2db7f1389dbd

这种进入方式,退出后容器就进入Down状态,如下

[root@2db7f1389dbd /]# exit
exit
[root@centos7 ~]# docker ps
CONTAINER ID   IMAGE  COMMAND   CREATED    STATUS    PORTS   NAMES

3)使用nsenter命令进入容器

[root@centos7 ~]# nsenter --help
Usage:
 nsenter [options] <program> [<argument>...]
Run a program with namespaces of other processes.
Options:
 -t, --target <pid>     target process to get namespaces from
 -m, --mount[=<file>]   enter mount namespace
 -u, --uts[=<file>]     enter UTS namespace (hostname etc)
 -i, --ipc[=<file>]     enter System V IPC namespace
 -n, --net[=<file>]     enter network namespace
 -p, --pid[=<file>]     enter pid namespace
 -U, --user[=<file>]    enter user namespace
 -S, --setuid <uid>     set uid in entered namespace
 -G, --setgid <gid>     set gid in entered namespace
     --preserve-credentials do not touch uids or gids
 -r, --root[=<dir>]     set the root directory
 -w, --wd[=<dir>]       set the working directory
 -F, --no-fork          do not fork before exec'ing <program>
 -Z, --follow-context   set SELinux context according to --target PID
 -h, --help     display this help and exit
 -V, --version  output version information and exit

获取容器的PID

[root@centos7 ~]# docker inspect --format "{{.State.Pid}}" 2db7f1389dbd 
4580
[root@centos7 ~]# nsenter -t 4580 -u -i -n -p
[root@2db7f1389dbd ~]# hostname
2db7f1389dbd
[root@2db7f1389dbd ~]# exit
logout
[root@centos7 ~]# docker ps
CONTAINER ID  IMAGE    COMMAND    CREATED    STATUS   PORTS  NAMES
2db7f1389dbd  centos    "/bin/bash" 22 minutes ago   Up 7 minutes  mgg

4)删除容器

[root@centos7 ~]# docker ps -a
CONTAINER ID   IMAGE  COMMAND   CREATED     STATUS    PORTS    NAMES
2db7f1389dbd  centos  "/bin/bash"  31 minutes ago  Up 16 minutes  mgg
3c113f9a4f1b  centos  "/bin/echo nihao" 38 minutes ago Exited (0) 38 minutes ago boring_liskov
[root@centos7 ~]# docker rm 3c113f9a4f1b  ##接名称也可以,删除一个停止的容器
3c113f9a4f1b
[root@centos7 ~]# docker rm -f   3c113f9a4f1b ##删除一个正在运行的容器
[root@centos7 ~]# docker ps -a          
CONTAINER ID  IMAGE   COMMAND    CREATED    STATUS    PORTS   NAMES
2db7f1389dbd    centos    "/bin/bash"    31 minutes ago   Up 16 minutes  mgg
[root@centos7 ~]# docker run --rm centos /bin/echo "hello"   ##创建时自动删除,用于测试
[root@centos7 ~]#docker --kill $(docker ps -a -q)            ##删除正在运行的容器

Docker网络模式

Dokcer 通过使用 Linux 桥接提供容器之间的通信,Docker的网络模式有四种

分别是以下四种模式:

  • host 模式,使用--net=host 指定。
  • container 模式,使用--net=container:NAMEorID 指定。
  • none 模式,使用--net=none 指定。
  • bridge 模式,使用--net=bridge 指定,默认配置
  • host 模式

如果容器使用 host 模式,那么容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡与配置 IP 等,而是使用宿主机的 IP 和端口。就和直接跑在宿主机中一样。但是容器的文件系统、进程列表等还是和宿主机隔离的。

  • container 模式

这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡与配置 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他方面仍然是隔离的。

  • none模式

此模式不同于前两种,Docker 容器有自己的 Network Namespace,但是,Docker容器没有任何网络配置。而是需要我们手动给 Docker容器添加网卡、配置 IP 等。

  • bridge 模式

此模式是Docker默认的网络设置,此模式会为每一个容器分配Network Namespace,并将一个主机上的Docker容器连接到一个虚拟网桥上。

更多关于Docker容器网络介绍请参考:Docker容器网络-基础篇Docker容器网络-实现篇

Docker数据存储

docker管理数据的方式有两种:

  • 数据卷
  • 数据卷容器

默认容器的数据是保存在容器的可读写层,当容器被删除时其上的数据也会丢失,所以为了实现数据的持久性则需要选择一种数据持久技术来保存数据。官方提供了三种存储方式:Volumes、Bind mounts和tmpfs。

数据存储方式

从现在开始,我们学习 Docker 容器的数据存储方式,你也可以先了解一下Docker 数据持久化的三种方案

Bind mount 会覆盖容器中的文件,而 volume mount 则不会。即如果容器中已有文件,则会将文件同步到主机的目录上。此方式与 Linux 系统的 mount 方式很相似,即是会覆盖容器内已存在的目录或文件,但并不会改变容器内原有的文件,当 umount 后容器内原有的文件就会还原。

数据卷(Volumes)

  • docker创建和管理,且与主机的核心功能隔离

  • 无论是命名还是匿名数据卷,都存储在/var/lib/docker/volumes/下面
  • 定义的数据卷可以在多个容器中同时使用,且不会自动删除
  • 允许容器将内容保存到远端、云服务提供商、加密内容等等

挂在主机目录(Bind mounts)

  • 与数据卷相比,挂在主机目录具有有限的功能
  • 应用的文件或者目录事先不需要存在,用时会自动创建
  • 该方式允许访问容器的敏感文件,可能会产生安全隐患

内存映射(tmpfs)

  • 仅存储在容器的内存中,永远不会写入文件系统
  • swarm服务使用tmpfs挂载将敏感信息挂载到容器中

数据卷 - volumes

数据卷是存储在 Docker 容器的特定目录下面

优势说明

Docker Volumes 机制通常用来给 Docker 容器保存持久化数据,使用 Volumes 有很多优势:

  • 更容易进行备份和数据迁移
  • 使用 Docker CLI 命令或者 Docker API 来管理
  • 可以在 Linux 和 Windows 操作系统上使用
  • 可以更安全得在多个容器中共享
  • Volume drivers 允许容器将内容保存到远端、云服务提供商、加密 volume 内容
  • 新 Volume 的内容可以被容器预先填充

Volumes 通常也优于容器的可写层,使用 Volumes 不会增加容器的体积,并且 Volumes 的内容存储在外部独立于容器的生命周期。如果容器不产生持久化数据,可以考虑使用 tmpfs 内存映射(只保存在容器的内存中)的方式来避免数据存储在其他可能的地方,避免增加容器的体积。

使用说明

最开始的时候 -v 或者 --volume 选项是给单独容器使用,而 --mount 选项是给集群服务使用。但是从 Docker 17.06 开始,也可以在单独容器上使用 --mount。通常来讲 --mount 选项也更加具体和详细。-v 选项将所有选项集中到一个值,而 --mount 选项将可选项分开。如果需要指定 volume driver 选项,那么必须使用 --mount 选项。

# 创建一个数据卷
$ docker volume create my-vol

# 查看所有的数据卷
$ docker volume ls

# 查看指定数据卷的信息
$ docker volume inspect my-vol
[
    {
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
        "Name": "my-vol",
        "Options": {},
        "Scope": "local"
    }
]

# 移除指定数据卷的
$ docker volume rm my-vol

# 清除无主的数据卷
$ docker volume prune
# 启动一个挂载数据卷的容器
$ docker run -d -P --name web \
    -v my-vol:/wepapp \
    training/webapp python app.py

$ docker run -d -P --name web \
    --mount source=my-vol,target=/webapp \
    training/webapp python app.py

# 启动一个挂载数据卷的服务
$ docker service create -d --name devtest-service \
    --mount source=myvol2,target=/app \
    nginx:latest
# 挂载为只读模式
$ docker run -d --name=nginxtest \
    -v nginx-vol:/usr/share/nginx/html:ro \
    nginx:latest

# type可以分为bind、volume、tmpfs, 默认为volume
# source用于设置数据卷的名称,匿名数据卷可以省略
# target表示需要挂载到容器里面的地方
# readonly表示挂载的内容为只读模式,可选
# volume-opt表示可以使用多次,可选
$ docker run -d --name=nginxtest \
    --mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \
    nginx:latest
[3] 挂载远程数据卷
# 插件sshfs允许您轻松地在容器中挂载远程文件夹

# 下载该插件
$ docker plugin install --grant-all-permissions vieux/sshfs

# 使用该驱动创建ssh数据卷
$ docker volume create --driver vieux/sshfs \
    -o sshcmd=test@node2:/home/test \
    -o password=testpassword \
    -o port=3336 \
    sshvolume

# 启动该驱动程序创建卷创建容器
# 如果两个容器配置了可信关系,就不需要设置volume-opt密码了
$ docker run -d \
    --name sshfs-container \
    --volume-driver vieux/sshfs \
    --mount data-original=sshvolume,target=/app, \
    volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword \
    nginx:latest

挂载主机目录 - bind mounts

挂载主机目录是将主机中的特定目录直接挂在到容器内部使用

使用说明
# 使用bind模式启动容器
$ docker run -d -it --name devtest \
    -v "$(pwd)"/target:/app \
    nginx:latest

$ docker run -d -it --name devtest \
    --mount type=bind,source="$(pwd)"/target,target=/app \
    nginx:latest

# 看下对应的信息
$ docker inspect devtest
"Mounts": [
    {
        "Type": "bind",
        "Source": "/tmp/source/target",
        "Destination": "/app",
        "Mode": "",
        "RW": true,
        "Propagation": "rprivate"
    }
]

# 挂载为只读模式
$ docker run -d -it --name devtest \
    -v "$(pwd)"/target:/app:ro \
    nginx:latest

$ docker run -d -it --name devtest \
    --mount type=bind,source="$(pwd)"/target,target=/app,readonly \
    nginx:latest

特殊属性

$ docker run -d -it --name devtest \
    -v "$(pwd)"/target:/app \
    -v "$(pwd)"/target:/app2:ro,rslave \
    nginx:latest

$ docker run -d -it --name devtest \
    --mount type=bind,source="$(pwd)"/target,target=/app \
    --mount type=bind,source="$(pwd)"/target,target=/app2,readonly,bind-propagation=rslave \
    nginx:latest

内存映射 - tmpfs

内存映射是将内存映射到容器内供容器内部使用

优势说明

最开始 --tmpfs 是给单独容器使用,而 --mount 选项是给 swarm 集群服务使用的。但是,从 Docker 17.06 开始,也可以在单独容器上使用 --mount 了。通常说来,--mount 更明确,更冗长。最大的区别是 --tmpfs 标志不支持任何可配置选项。其中 --tmpfs 只能在容器中使用,而 swarm 集群则必须使用 --mount 来使用 tmpfs 内存映射。

使用说明

# 容器上使用
$ docker run -d -it --name tmptest \
    --tmpfs /app \
    nginx:latest

$ docker run -d -it --name tmptest \
    --mount type=tmpfs,destination=/app \
    nginx:latest

日志驱动 - logs

在容器外部查看容器内部的日志输出情况,便于排除和监控问题

可以利用 docker logs 命令,查看 Docker 容器内部应用程序运行时所产生的日志。可以免除首先进入 Docker 容器,再打开应用程序的日志文件的过程。docker logs 会监控容器中操作系统的标准输出设备(STDOUT),一旦 STDOUT 有数据产生,就会将这些数据传输到另一个设备中,则被称为日志驱动(Logging Driver)。

# 动态查看日志内容
$ docker logs -f netdata
Docker 是怎样做到的呢?我们使用 docker info 命令,可以看到 Docker 容器的相关信息,其中有一项 Logging Driver 的字段。

# 当前所设置的日志驱动类型
$ docker info | grep 'Logging Driver'
Logging Driver: json-file

我们可以在 docker run 命令中通过 --log-driver 参数来设置具体的 Docker 日志驱动,也可以通过 --log-opt 参数来指定对应日志驱动的相关选项。

docker run -d -p 80:80 --name nginx \    
--log-driver json-file \ # 设置日志驱动    
--log-opt max-size=10m \ # 表示JSON文件最大为10MB,超过则生成新的文件    
--log-opt max-file=3 \   # 表示JSON文件最多保存3个,超过则删除多余文件    
nginx
# 当然,可以在配置文件中添加,全局生效
$ cat /etc/docker/daemon.json
{
  "log-driver": "syslog"
}

# 修改配置之后重启服务
$ sudo systemctl restart docker

额外,需要注意的是,默认情况下,Docker 将日志存储到一个日志文件。

# 检查日志文件路径
$ docker inspect --format='{{.LogPath}}' netdata
/var/lib/docker/containers/556553bcb5xxx13cbc588a4-json.log

# 查看实时日志信息
$ tail -f `docker inspect --format='{{.LogPath}}' netdata`

上述内容参考: https://escapelife.github.io/...

Docker Command 介绍

安装完成docker容器服务之后,需要了解如何操作它?在shell命令行下直接输入docker就可以查看帮助信息,如下。

[root@master ~]# docker
Usage:    docker COMMAND
A self-sufficient runtime for containers

Options:
      --config string      Location of client config files (default "/root/.docker")
  -D, --debug              Enable debug mode
      --help               Print usage
  -H, --host list          Daemon socket(s) to connect to (default [])
  -l, --log-level string   Set the logging level ("debug", "info", "warn", "error", "fatal") (default "info")
      --tls                Use TLS; implied by --tlsverify
      --tlscacert string   Trust certs signed only by this CA (default "/root/.docker/ca.pem")
      --tlscert string     Path to TLS certificate file (default "/root/.docker/cert.pem")
      --tlskey string      Path to TLS key file (default "/root/.docker/key.pem")
      --tlsverify          Use TLS and verify the remote
  -v, --version            Print version information and quit

Management Commands:
  container   Manage containers
  image       Manage images
  network     Manage networks
  node        Manage Swarm nodes
  plugin      Manage plugins
  secret      Manage Docker secrets
  service     Manage services
  stack       Manage Docker stacks
  swarm       Manage Swarm
  system      Manage Docker
  volume      Manage volumes

Commands:
  attach      Attach to a running container
  build       Build an image from a Dockerfile
  commit      Create a new image from a container's changes
  cp          Copy files/folders between a container and the local filesystem
  create      Create a new container
  diff        Inspect changes on a container's filesystem
  events      Get real time events from the server
  exec        Run a command in a running container
  export      Export a container's filesystem as a tar archive
  history     Show the history of an image
  images      List images
  import      Import the contents from a tarball to create a filesystem image
  info        Display system-wide information
  inspect     Return low-level information on Docker objects
  kill        Kill one or more running containers
  load        Load an image from a tar archive or STDIN
  login       Log in to a Docker registry
  logout      Log out from a Docker registry
  logs        Fetch the logs of a container
  pause       Pause all processes within one or more containers
  port        List port mappings or a specific mapping for the container
  ps          List containers
  pull        Pull an image or a repository from a registry
  push        Push an image or a repository to a registry
  rename      Rename a container
  restart     Restart one or more containers
  rm          Remove one or more containers
  rmi         Remove one or more images
  run         Run a command in a new container
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
  search      Search the Docker Hub for images
  start       Start one or more stopped containers
  stats       Display a live stream of container(s) resource usage statistics
  stop        Stop one or more running containers
  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
  top         Display the running processes of a container
  unpause     Unpause all processes within one or more containers
  update      Update configuration of one or more containers
  version     Show the Docker version information
  wait        Block until one or more containers stop, then print their exit codes

命令很多,重点介绍这20个,请详细阅读下面的文章:

这20个Docker Command,有几个是你会的?

Docker file

Docker file简单介绍

Docker可以使用Dockerfile的内容来自动构建镜像。Dockerfile也是一个文件,其中有创建镜像、运行指令等一系列的命令,且每行只支持一个运行命令。

Docker file分为四部分组成:

  • 基础镜像信
  • 维护者信息
  • 镜像操作指令
  • 容器启动时执行指令

dockerfile指令忽略大小写,建议大写,#作为注释,每行只支持一条指令,指令可以带多个参数。

dockerfile指令有:

  • 构建指令:用于构建image,其指定的操作不会在运行image的容器中执行。
  • 设置指令:用于设置image的属性,其指定的操作会在运行image的容器中执行。

Dockerfile指令

Dockerfile指令一共有以下种:

  • 1、FROM

用来指定基础镜像,然后通过在基础镜像上构建新的镜像,基础镜像一般有远程或本地仓库。并且Dockerfile文件第一行必须的FROM指令,如果一个Dockerfile需要创建多个镜像,可以使用多个FROM指令。

#具体使用用法如下:
FROM < image_name >   #默认是latest版本
FROM <image:version>  #指定版本
  • 2、MAINTAINER

指定镜像的创建者信息

#具体使用法如下:
MAINTAINER < name >
  • 3、RUN

运行所有基础镜像能支持的命令,同样也可以使用多条RUN指令,可以使用\来换行

#具体使用法如下:
RUN < command >
RUN ["executable", "param1", "param2" ... ] (exec form) 
  • 4、CMD

用于容器启动时的指定操作,它可以是命令,也可以是脚本,但只执行一次,如果有多少默认只会执行最后一个。

#具体使用法如下:
CMD [“executable” ,”Param1”, “param2”]使用exec执行,推荐 
CMD command param1 param2,在/bin/sh上执行 
CMD [“Param1”, “param2”] 提供给ENTRYPOINT做默认参数。
  • 5、EXPOSE

指定容器的端口映射(容器与物理机),运行容器时加上-p参数指定EXPOSE设置的端口。EXPOSE可以设置多个端口号,相应地运行容器配套多次使用-p参数。可以通过docker port +容器需要映射的端口号和容器ID来参考宿主机的映射端口。

#具体使用法如下:
EXPOSE <port> [port1 , port2 ............]
  • 6、ENV

在镜像中用于设置环境变量的,然后RUN命令可以使用此设置的环境变量,在容器启动后也以通过docker inspect查看环境变量,可以通过docker run --env key=value来设置或修改环境变量。

#具体使用法如下:
ENV <key> <value>
ENV JAVA_HOME /usr/local/jdk
  • 7、ADD

复制指定的源文件、目录、URL到容器的指定目录中。所有拷贝到container中的文件和文件夹权限为0755,uid和gid为0。

如果源是一个目录,那么会将该目录下的所有文件添加到container中,不包括目录;

如果源文件是可识别的压缩格式,则docker会帮忙解压缩(注意压缩格式);

如果源是文件且目标目录中不使用斜杠结束,则会将目标目录视为文件,源的内容会写入目标目录;

如果源是文件且目标目录中使用斜杠结束,则会源文件拷贝到目标目录下。

#具体使用法如下:
ADD <源> <目标>
  • 8、COPY

复制本地主机的源(默认为Dockerfile所在的目录)到容器中的目标中,目标路径不存在时会自动创建。

#具体使用法如下:
COPY <源> <目标>
COPY web/index.html  /var/web/
  • 路径必须是绝对路径,如果不存在,会自动创建对应目录
  • 路径必须是Dockerfile 所在路径的相对路径
  • 如果是一个目录,只会复制目录下的内容,而目录本身则不会被复制
  • 9、ENTRYPOINT

指定容器启动后执行的命令,多行只执行最后一行。并且不可被docker run提供的参数覆盖。

#具体使用法如下:
ENTRYPOINT "command" "param1" "param2"
  • 10、VOLUME

创建一个可以从本地主机或其它容器挂载的挂载点,一般用于存放数据。与docker run -v也可以实现此功能。

#具体使用法如下:
VOLUME  [directory_name]
VOLUME /docker_data
  • 11、USER

指定容器运行时使用的用户或UID,后面RUN、CMD、ENTRYPIONT都会使用此用户来运行命令。

#具体使用法如下:
USER [username/uid]
  • 12、WORKDIR

指定RUN、CMD、ENTRYPIONT指定的命令的运行目录。可以使用多个WORKDIR指令,后续参数如果是相对路径,则会基于之前的命令指定的路径。如:WORKDIR /data WORKDIR work。最终的路径就是/data/work。path路径也可以是环境变量。

#具体使用方法如下:
WORKDIR [path]
  • 13、ONBUILD

配置当前所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令。就是,这个镜像创建后,如果其它镜像以这个镜像为基础,会先执行这个镜像的ONBUILD命令。

#具体使用法如下:
ONBUILD [INSTRUCTION]

通过Dockerfile快速构建镜像

接下来,我们通过构建一个Tomcat镜像,来演示Dockerfile的使用方法,前提是安装Docker环境,如何安装Docker环境就不在此赘述了。请猛戳下面的文字:

[root@master tomcat]# ll
总用量 190504
-rw-r--r-- 1 root root   9552281 6月   7 15:07 apache-tomcat-8.5.31.tar.gz
-rw-r--r-- 1 root root        32 7月   3 09:41 index.jsp
-rw-r--r-- 1 root root 185515842 9月  20 2017 jdk-8u144-linux-x64.tar.gz
[root@master tomcat]# cat index.jsp 
welcome to mingongge's web site
[root@master tomcat]# pwd
/root/docker/tomcat
[root@master tomcat]# vim Dockerfile
#config file start#
FROM centos
MAINTAINER mingongge <微信公众号:民工哥技术之路>

#add jdk and tomcat software
ADD jdk-8u144-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-8.5.31.tar.gz /usr/local/
ADD index.jsp /usr/local/apache-tomcat-8.5.31/webapps/ROOT/

#config java and tomcat ENV
ENV JAVA_HOME /usr/local/jdk1.8.0_144
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.31/
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin

#config listen port of tomcat
EXPOSE 8080

#config startup command of tomcat
CMD /usr/local/apache-tomcat-8.5.31/bin/catalina.sh run

#end of config-file#

构建过程

[root@master tomcat]# docker build -t tomcat-web . #这个.不用注释了吧相信懂的人自然懂的
Sending build context to Docker daemon 195.1 MB
Step 1/11 : FROM centos
 ---> 49f7960eb7e4
Step 2/11 : MAINTAINER mingongge <微信公众号:民工哥技术之路>
 ---> Running in afac1e218299
 ---> a404621fac22
Removing intermediate container afac1e218299
Step 3/11 : ADD jdk-8u144-linux-x64.tar.gz /usr/local/
 ---> 4e22dafc2f76
Removing intermediate container b1b23c6f202a
Step 4/11 : ADD apache-tomcat-8.5.31.tar.gz /usr/local/
 ---> 1efe59301d59
Removing intermediate container aa78d5441a0a
Step 5/11 : ADD index.jsp /usr/local/apache-tomcat-8.5.31/webapps/ROOT/
 ---> f09236522370
Removing intermediate container eb54e6eb963a
Step 6/11 : ENV JAVA_HOME /usr/local/jdk1.8.0_144
 ---> Running in 3aa91b03d2d1
 ---> b497c5482fe0
Removing intermediate container 3aa91b03d2d1
Step 7/11 : ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
 ---> Running in f2649b5069be
 ---> 9cedb218a8df
Removing intermediate container f2649b5069be
Step 8/11 : ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.31/
 ---> Running in 39ef620232d9
 ---> ccab256164fe
Removing intermediate container 39ef620232d9
Step 9/11 : ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin
 ---> Running in a58944d03d4a
 ---> f57de761a759
Removing intermediate container a58944d03d4a
Step 10/11 : EXPOSE 8080
 ---> Running in 30681437d265
 ---> b906dcc26584
Removing intermediate container 30681437d265
Step 11/11 : CMD /usr/local/apache-tomcat-8.5.31/bin/catalina.sh run
 ---> Running in 437790cc642a
 ---> 95204158ee68
Removing intermediate container 437790cc642a
Successfully built 95204158ee68

通过构建的镜像启动容器

[root@master tomcat]# docker run -d -p 8080:8080 tomcat-web
b5b65bee5aedea2f48edb276c543c15c913166bf489088678c5a44fe9769ef45
[root@master tomcat]# docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED        STATUS         PORTS                    NAMES
b5b65bee5aed   tomcat-web   "/bin/sh -c '/usr/..."   5 seconds ago  Up 4 seconds   0.0.0.0:8080->8080/tcp   vigilant_heisenberg

访问容器

浏览器输入http://server-ip:8080, 结果如下:

Docker三剑客

容器技术|Docker三剑客之Compose

容器技术|Docker三剑客之docker-machine

打造高逼格、可视化的Docker容器监控系统平台

私有镜像仓库搭建

当我们执行docker pull xxx的时候,docker默认是从registry.docker.com这个地址上去查找我们所需要的镜像文件,然后执行下载操作。这类的镜像仓库就是docker默认的公共仓库,所有人都可以直接查看或下载、使用,但是呢,基于网络原因,下载速度有限制比较慢。因此,我们在公司内部内网环境中使用dokcer,一般不会将镜像文件上传到公网公共库中。但内部共享使用就是个问题,所以,私有仓库就由此产生了。

什么是私有仓库?

私有仓库,就是本地(内网环境)组建的一个与公网公共库功能相似的镜像仓库。组建好之后,我们就可以将打包好的镜像提交到私有仓库中,这样内网其它用户也可以使用这个镜像文件。

本文使用官方提供的registry镜像来组建企业内网的私有镜像仓库

环境介绍

两台安装好docker环境的主机

  • 服务端:192.168.3.82 私有仓库服务器在,运行registry容器
  • 客户端:192.168.3.83 测试客户端,用于上传、下载镜像文件

安装布署过程

下载官方registry镜像文件

[root@master ~]# docker pull registry
Using default tag: latest
Trying to pull repository docker.io/library/registry ... 
latest: Pulling from docker.io/library/registry
81033e7c1d6a: Pull complete 
b235084c2315: Pull complete 
c692f3a6894b: Pull complete 
ba2177f3a70e: Pull complete 
a8d793620947: Pull complete 
Digest: sha256:672d519d7fd7bbc7a448d17956ebeefe225d5eb27509d8dc5ce67ecb4a0bce54
Status: Downloaded newer image for docker.io/registry:latest
[root@master ~]# docker images |grep registry
docker.io/registry   latest  d1fd7d86a825   5 months ago  33.3 MB

运行registry容器

[root@master ~]# mkdir /docker/registry -p
[root@master ~]# docker run -itd -v /docker/registry/:/docker/registry -p 5000:5000 --restart=always --name registry registry:latest
26d0b91a267f684f9da68f01d869b31dbc037ee6e7bf255d8fb435a22b857a0e
[root@master ~]# docker ps
CONTAINER ID   IMAGE            COMMAND                  CREATED        STATUS        PORTS                    NAMES
26d0b91a267f   registry:latest  "/entrypoint.sh /e..."   4 seconds ago  Up 3 seconds  0.0.0.0:5000->5000/tcp   registry

参数说明

1)-itd:在容器中打开一个伪终端进行交互操作,并在后台运行;
2)-v:把宿主机的/docker/registry目录绑定到容器/docker/registry目录(这个目录是registry容器中存放镜像文件的目录),来实现数据的持久化;
3)-p:映射端口;访问宿主机的5000端口就访问到registry容器的服务了;
4)--restart=always:这是重启的策略,假如这个容器异常退出会自动重启容器;
5)--name registry:创建容器命名为registry,可自定义任何名称;
6)registry:latest:这个是刚才pull下来的镜像;

查看远程仓库镜像文件

[root@master ~]# curl http://localhost:5000/v2/_catalog
{"repositories":[]}

同样也可以使用浏览器访问http://server-ip:5000/v2/_cat... 结果相同,都是空的没有任何文件。

客户端操作

修改下载的镜像源

[root@slave1 ~]# vim /etc/docker/daemon.json
{
"registry-mirrors":["https://registry.docker-cn.com"]
}
[root@slave1 ~]# systemctl restart docker

下载测试镜像

[root@slave1 ~]# docker pull nginx
Using default tag: latest
Trying to pull repository docker.io/library/nginx ... 
latest: Pulling from docker.io/library/nginx
683abbb4ea60: Pull complete 
6ff57cbc007a: Pull complete 
162f7aebbf40: Pull complete 
Digest: sha256:636dd2749d9a363e5b57557672a9ebc7c6d041c88d9aef184308d7434296feea
Status: Downloaded newer image for docker.io/nginx:latest

给镜像打TAG

[root@slave1 ~]# docker tag nginx:latest 192.168.3.82:5000/nginx:v1
[root@slave1 ~]# docker images
REPOSITORY                TAG       IMAGE ID        CREATED       SIZE
192.168.3.82:5000/nginx   v1        649dcb69b782    8 hours ago   109 MB
docker.io/nginx           latest    649dcb69b782    8 hours ago   109 MB

上传镜像

[root@slave1 ~]# docker push 192.168.3.82:5000/nginx:v1
The push refers to a repository [192.168.3.82:5000/nginx]
Get https://192.168.3.82:5000/v1/_ping: http: server gave HTTP response to HTTPS client
#注意这里出现报错提示,从提示信息可以看出需要使用https的方式才能上传,解决方案如下:
[root@slave1 ~]# vim /etc/docker/daemon.json
{
"registry-mirrors":["https://registry.docker-cn.com"],
 "insecure-registries":["192.168.3.82:5000"]
}
#添加私有镜像服务器的地址,注意书写格式为json,有严格的书写要求,需要重启docker服务生效配置
[root@slave1 ~]# systemctl restart docker
[root@slave1 ~]# docker push 192.168.3.82:5000/nginx:v1
The push refers to a repository [192.168.3.82:5000/nginx]
6ee5b085558c: Pushed 
78f25536dafc: Pushed 
9c46f426bcb7: Pushed 
v1: digest: sha256:edad5e71815c79108ddbd1d42123ee13ba2d8050ad27cfa72c531986d03ee4e7 size: 948

重新查看镜像仓库

[root@master ~]# curl http://localhost:5000/v2/_catalog
{"repositories":["nginx"]}
[root@master ~]# curl http://localhost:5000/v2/nginx/tags/list
{"name":"nginx","tags":["v1"]}
#查看有哪些版本

测试下载

#首先删除客户端主机之前从公共库下载下来的镜像文件
[root@slave1 ~]# docker images
REPOSITORY                TAG      IMAGE ID        CREATED        SIZE
192.168.3.82:5000/nginx   v1       649dcb69b782    10 hours ago   109 MB
docker.io/nginx           latest   649dcb69b782    10 hours ago   109 MB
[root@slave1 ~]# docker image rmi -f 649dcb69b782
Untagged: 192.168.3.82:5000/nginx:v1
Untagged: 192.168.3.82:5000/nginx@sha256:edad5e71815c79108ddbd1d42123ee13ba2d8050ad27cfa72c531986d03ee4e7
Untagged: docker.io/nginx:latest
Untagged: docker.io/nginx@sha256:636dd2749d9a363e5b57557672a9ebc7c6d041c88d9aef184308d7434296feea
Deleted: sha256:649dcb69b782d4e281c92ed2918a21fa63322a6605017e295ea75907c84f4d1e
Deleted: sha256:bf7cb208a5a1da265666ad5ab3cf10f0bec1f4bcb0ba8d957e2e485e3ac2b463
Deleted: sha256:55d02c20aa07136ab07ab47f4b20b97be7a0f34e01a88b3e046a728863b5621c
Deleted: sha256:9c46f426bcb704beffafc951290ee7fe05efddbc7406500e7d0a3785538b8735
[root@slave1 ~]# docker images
REPOSITORY       TAG             IMAGE ID        CREATED         SIZE
#此时客户端所有的镜像文件全部删除
[root@slave1 ~]# docker pull 192.168.3.82:5000/nginx:v1
Trying to pull repository 192.168.3.82:5000/nginx ... 
v1: Pulling from 192.168.3.82:5000/nginx
683abbb4ea60: Pull complete 
6ff57cbc007a: Pull complete 
162f7aebbf40: Pull complete 
Digest: sha256:edad5e71815c79108ddbd1d42123ee13ba2d8050ad27cfa72c531986d03ee4e7
Status: Downloaded newer image for 192.168.3.82:5000/nginx:v1
[root@slave1 ~]# docker images
REPOSITORY                TAG     IMAGE ID       CREATED         SIZE
192.168.3.82:5000/nginx   v1      649dcb69b782   11 hours ago    109 MB
#可以看出,客户端已正常从远端服务器拉取到所需要的镜像文件,其它内网服务器也可以正常共享这台镜像服

以上步骤就是通过使用docker Registry快速搭建私有镜像仓库的过程与测试。我也其实也可以通过:利用 Harbor 搭建企业级私有镜像仓库

Docker可视化工具

Docker是一项非常流行的容器技术,现在在各行各业有着广泛的使用。不过如何管理Docker容器是一个问题,所以我今天向大家介绍两款Docker可视化工具,希望对大家有所帮助。

Portainer

Portainer是一款Docker可视化管理工具,允许我们在网页中方便的查看和管理Docker容器。

要使用Portainer很简单,运行下面两条命令即可。这些命令会创建一个Portainer专用的卷,然后在8000和9000端口创建容器并运行。

$ docker volume create portainer_data$ docker run --name portainer -d -p 8000:8000 -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer

然后在浏览器打开对应地址,就会发现成功运行了。第一次运行的时候需要设置账号,然后选择要管理的Docker主机。

设置账号

选择要管理的主机

之后就可以看到本机上运行的Docker容器了,点击它们还可以进行容器的管理。左边的条目可以管理卷、创建容器、查看主机信息等等。基本上该有的功能都有了,这也是我推荐的一个工具。

LazyDocker

LazyDocker是基于终端的一个可视化查询工具,支持键盘操作和鼠标点击。相比Portainer来说可能不那么专业,不过对于开发者来说可能反而更加好用了。因为一般开发者都是使用命令行来运行Docker,偶尔需要图形化查看的时候,就可以使用LazyDocker这个工具。

官网演示图

安装LazyDocker也非常简单,运行下面的命令即可。

docker run --rm -it -v \/var/run/docker.sock:/var/run/docker.sock \-v ~/.config/lazydocker:/.config/jesseduffield/lazydocker \lazyteam/lazydocker

当然如果发现LazyDocker挺好用,准备经常使用的话,还可以把它做成缩写添加到shell配置文件中,这样就可以将它变成一个简单的命令。例如我用的是zsh,就将下面这样添加到.zshrc文件中。以后就可以直接用lzd来调用LazyDocker了。

alias lzd='docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock -v ~/.config/lazydocker:/.config/jesseduffield/lazydocker lazyteam/lazydocker'

然后就可以在终端中查看Docker容器、镜像和卷的信息了。LazyDocker支持键盘操作和鼠标点击,直接用鼠标点击就可以查看对应信息了。

需要注意如果你的终端LazyDocker的图形显示的是乱的,不用担心,只不过是显示字体的问题。重新设置一下终端字体就可以解决了。

以上内容来自:https://www.toutiao.com/i6780...

Docker 社区已经创建了许多开源工具,它们能帮我们处理各种用例。作者在本文中推荐了 5 款认为最有用的 Docker 工具,分别是 Watchtower(自动更新 Docker 容器)、docker-gc(容器和镜像的垃圾回收)、docker-slim(容器瘦身)、 rocker:突破 Dockerfile 的限制,以及 ctop(容器的类顶层接口)。
Docker 社区已经创建了许多开源工具,它们所能帮你处理的用例甚至会超出你的想象。
你可以在网上找到很多酷炫的 Docker 工具,其中大部分是开源的,都可以在 Github 上找到。在过去的两年里,我非常热衷于 Docker,在大多数开发项目中都使用了它。当你开始使用 Docker 后,你会发现它适用的场景比你最初预想的还更多。你会希望 Docker 尽可能为你多做一点事,而它不会让你失望的!
Docker 社区非常活跃,每天都会出现许多有用的工具,时时关注社区中发生的所有创新是很困难的。为了帮助你,我收集了一些我在日常工作中使用的又有趣又实用的 Docker 工具,这些工具提升了我的工作效率,减少了原本需要手工完成的工作。

向大家推荐一些实用工具:你应该知道的5个开源Docker工具...,Docker 服务终端 UI 管理工具,大家最终根据自己的使用习惯与实际生产需求来选择合适自己的工具来管理Docker容器。

Docker容器监控系统

随着线上服务的全面docker化,对docker容器的监控就很重要了。SA的监控系统是物理机的监控,在一个物理机跑多个容器的情况下,我们是没法从一个监控图表里面区分各个容器的资源占用情况的。

推荐大家看看这篇:打造高逼格、可视化的Docker容器监控系统平台

Docker 日志管理最佳实践

10 个冷门但又非常实用的 Docker 使用技巧

在平时的工作中,docker 接触得很多,除了经常使用的 docker run ,docker stop 等命令,docker 还有很多十分有用但是却不经常使用的命令,下面就来总结一下:

1. docker top

这个命令是用来查看一个容器里面的进程信息的,比如你想查看一个 nginx 容器里面有几个 nginx 进程的时候,就可以这么做:

docker top 3b307a09d20d
UID      PID    PPID    C    STIME  TTY    TIME       CMD
root     805    787     0    Jul13   ?   00:00:00  nginx: master process nginx -g daemon off;
systemd+ 941     805     0   Jul13    ?   00:03:18  nginx: worker process

2. docker load && docker save

我一般使用这两个命令去下载打包 Kubernetes 的镜像,因为你知道的国内的网速并不像国外那么快。

docker save 可以把一个镜像保存到 tar 文件中,你可以这么做:

~ docker save registry:2.7.1 >registry-2.7.1.tar
#同时 docker load 可以把镜像从 tar 文件导入到 docker 中
~ docker load < registry-2.7.1.tar

3. docker search

这个命令可以帮助你在命令行中方便的搜索 DockerHub 中的镜像,比如:

~ docker search nginx
NAME                               DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
nginx                              Official build of Nginx.                        13519               [OK]
jwilder/nginx-proxy                Automated Nginx reverse proxy for docker con…   1846                                    [OK]
richarvey/nginx-php-fpm            Container running Nginx + PHP-FPM capable of…   780                                     [OK]
linuxserver/nginx                  An Nginx container, brought to you by LinuxS…   123
bitnami/nginx                      Bitnami nginx Docker Image                      87                                      [OK]
tiangolo/nginx-rtmp                Docker image with Nginx using the nginx-rtmp…   85                                      [OK]
jc21/nginx-proxy-manager           Docker container for managing Nginx proxy ho…   73
alfg/nginx-rtmp                    NGINX, nginx-rtmp-module and FFmpeg from sou…   71                                      [OK]
nginxdemos/hello                   NGINX webserver that serves a simple page co…   57                                      [OK]
jlesage/nginx-proxy-manager        Docker container for Nginx Proxy Manager        53                                      [OK]
nginx/nginx-ingress                NGINX Ingress Controller for Kubernetes         37
......

当然这个功能在国内可能不会特别好用,因为......

4. docker events

这个命令可以帮助你实时获取 docker 的各种事件信息,比如创建了一个容器什么的。

~ docker events
2020-07-28T21:28:46.000403018+08:00 image load sha256:432bf69f0427b52cad10897342eaf23521b7d973566354118e9a59c4d31b5fae (name=sha256:432bf69f0427b52cad10897342eaf23521b7d973566354118e9a59c4d31b5fae)

5. docker update

当你 docker run 了之后却发现里面有一些参数并不是你想要的状态比如你设置的 nginx 容器 cpu 或者内存太小,这个时候你就可以使用 docker update 去修改这些参数。

~ docker update nginx --cpus 2

6. docker history

当你修改了一个镜像,但是忘记了每一层的修改命令,或者你想查看一个镜像是怎么构建的时候就可以使用这个命令,比如:

~ docker history  traefik:v2.1.6
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
5212a87ddaba        5 months ago        /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
<missing>           5 months ago        /bin/sh -c #(nop)  CMD ["traefik"]              0B
<missing>           5 months ago        /bin/sh -c #(nop)  ENTRYPOINT ["/entrypoint.…   0B
<missing>           5 months ago        /bin/sh -c #(nop)  EXPOSE 80                    0B
<missing>           5 months ago        /bin/sh -c #(nop) COPY file:59a219a1fb7a9dc8…   419B
<missing>           5 months ago        /bin/sh -c set -ex;  apkArch="$(apk --print-…   52.9MB
<missing>           5 months ago        /bin/sh -c apk --no-cache add ca-certificate…   1.85MB
<missing>           6 months ago        /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
<missing>           6 months ago        /bin/sh -c #(nop) ADD file:a1906f14a4e217a49…   4.81MB

7. docker wait

这个命令可以查看容器的退出状态,比如:

~ docker wait 7f7f0522a7d0
0

这样你就可以知道这个容器是正常退出的还是异常退出的了。

8. docker pause && docker unpause

当你运行了一个容器但是想要暂停它运行的时候,你就可以使用这个命令。

~ docker pause 7f7f0522a7d0

9. docker diff

当你运行了一个容器,但是你不知道容器里修改了哪一些文件的时候可以使用这个命令,比如:

~ docker diff 38c59255bf6e
C /etc
A /etc/localtime
C /var
C /var/lib
A /var/lib/registry

10. docker stats

这个是 docker 内置的监控命令,当你想要查看当前主机下所有容器占用内存和 cpu 的情况的时候就可以使用这个命令。

~ docker stats

CONTAINER ID        NAME                        CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
1c5ade04e7f9        redis                        0.08%               17.53MiB / 47.01GiB   0.04%               10.9GB / 37GB       0B / 0B             4
afe6d4ebe409        kafka-exporter                0.09%               16.91MiB / 47.01GiB   0.04%               1.97GB / 1.53GB     752MB / 0B          23
f0c7c01a9c34        kafka-docker_zookeeper         0.01%               308.8MiB / 47.01GiB   0.64%               20.2MB / 12.2MB     971MB / 3.29MB      28
da8c5008955f        kafka-docker_kafka-manager     0.08%               393.2MiB / 47.01GiB   0.82%               1.56MB / 2.61MB     1.14GB / 0B         60
c8d51c583c49        kafka-docker_kafka            1.63%               1.256GiB / 47.01GiB   2.67%               30.4GB / 48.9GB     22.3GB / 5.77GB     85
......

原文:http://suo.im/6n2lLa

学习Docker,新手最容易犯的11个错误!

很多人最终还是决定使用 Docker 解决问题。 Docker 的优点很多,比如:

  • 1、一体化——将操作系统、库版本、配置文件、应用程序等全部打包装在容器里。从而保证 QA 所测试的镜像 (image) 会携带同样的行为到达生产环境。
  • 2、轻量——内存占用极小,只为主要过程分配内存。
  • 3、快读——一键启动,就像启动常见的 linux 过程一样快。

尽管如此,众多用户仍然只是把容器当做常见的虚拟机,而忘记了容器的一个重要特性:
正因为这一特点,一些用户需要改变他们对容器的观念,为了更好的使用与发挥 Docker 容器的价值,有一些事情是绝对不应该做的:

1.不要在容器(container)中存储数据

容器可能会被中断、被替换或遭到破坏。在容器中运行的 1.0 版应用程序很容易就会被 1.1 版取代,而不会对数据造成影响或导致数据丢失。因此,如果需要存储数据,请存储在卷 (volume) 中。在这一情况下,还应注意两个容器是否会在同一个卷上写入数据,这将导致损坏。请确保应用程序适用于写入共享的数据存储。

2. 不要分两部分传送应用程序 有些人把容器当作虚拟机

所以他们大多会认为,应该将应用程序部署到现有正在运行的容器中。在需要不断部署和调试的开发阶段,可能确实如此;但对于 QA 和生产的持续交付 (CD) 渠道,应用程序应当是镜像的一部分。切记:容器转瞬即逝。

3. 不要创建大尺寸镜像

大尺寸的镜像难以分配。请确保仅使用必需文件和库来运行应用程序。不要安装不必要的数据包,也不要运行“更新”(yum update),这些操作会把大量文件下载到新的镜像层。

4. 不要使用单层镜像

为了有效利用多层文件系统,请始终为操作系统创建属于自己的基本镜像层,然后为用户名定义创建一个层,为运行时安装创建一个层,为配置创建一个层,最后再为应用程序创建一个层。这样,重新创建、管理和分配镜像就会容易些。

5. 不要从正在运行的容器中创建镜像

换句话说,不要使用"docker commit"命令来创建镜像。这一镜像创建方法不可复制,因此应完全避免使用。请始终使用 Dockerfile 或其他任何可完全复制的 S21(从源代码到镜像)方法,如此一来,如果存储在源代码控制存储库 (GIT) 中,就可以跟踪 Dockerfile 的变更情况。

6. 不要只使用“最新版”标签

最新版标签就像 Maven 用户的“快照”(SNAPSHOT) 一样。容器具有多层文件系统这一基本特征,所以我们鼓励使用标签。相信谁也不愿意在构建了几个月的镜像后,突然发现应用程序因为父层(即 Dockerfile 中的 FROM)被新版本取代而无法运行(新版本无法向后兼容或从构建缓存中检索的“最新“版有误)这样的意外吧?在生产过程中部署容器时也应避免使用”最新版“标签,这是因为无法跟踪当前运行的镜像版本。

7. 不要在单个容器中运行一个以上进程

容器只运行一个进程(HTTP 守护进程、应用程序服务器、数据库)时效果最佳,但如果运行一个以上进程,在管理和检索日志以及单独更新进程时就会遇到很多麻烦。

8. 不要在镜像中存储证书及使用环境变量

不要在镜像中对任何用户名/密码进行硬编码操作。请使用环境变量从容器外部检索信息。Postgres 镜像就是这一原理的极佳诠释。

9. 不要以 root 权限运行进程

“默认情况下,Docker 容器以 root 用户权限运行。随着 Docker 技术日趋成熟,能够使用的安全默认选项越来越多。目前,要求 root 对其他用户来说较为危险,另外,不是所有环境都能够使用 root。镜像应使用 USER 指令来为容器的运行指定非 root 用户。”(摘自《Docker 镜像作者指南》(Guidance for Docker Image Authors))

10. 不要依赖 IP 地址

每个容器都有自己的内部 IP 地址,如果启动然后停止容器,内部 IP 地址可能会发生变化。如果你的应用程序或微服务需要和另一个容器进行通信,请使用环境变量在容器之间传递相应的主机名和端口。

11. 监控容器 Docker

监控已经越来越受到开发者们的重视,实时监控 Docker 的方法,这里推荐 Cloudinsight。 不同于一些需要自写脚本的监控手段,Cloudinsight 作为一家免费的 SaaS 服务,能够一键监控 Docker,且拥有很棒的可视化界面。除此之外,Cloudinsight 还支持多种操作系统、数据库等的监控,能够一体化展示所有被监控的系统基础组件的性能数据。

原文:https://my.oschina.net/cllgee...

Jenkins与Docker的自动化CI/CD实战

一、发布流程设计

工作流程:

  • 开发人员提交代码到Git版本仓库;
  • Jenkins人工/定时触发项目构建;
  • Jenkins拉取代码、代码编码、打包镜像、推送到镜像仓库;
  • Jenkins在Docker主机创建容器并发布。

三、 部署过程

1,部署git

如果公司内部有直接克隆就可以

git clone git@192.168.0.31:/home/git/solo.git

2,部署Jenkins环境

部署传送门:Jenkins+Maven+Svn实现代码自动打包与发布

3,部署私有镜像仓库

注意:docker 仓库 由于https 认证,所有需要pull的客户端,需要修改配置文件

[root@linux-node1 ~]# vim /etc/sysconfig/docker
# Modify these options if you want to change the way the docker daemon runs
 OPTIONS='--selinux-enabled --insecure-registry 192.168.56.11:5000'

4,所有主机安装docker

1)安装依赖包
yum install -y yum-utils device-mapper-persistent-data lvm2`
 
2)添加Docker软件包源:
yum-config-manager 
--add-repo 
https://download.docker.com/linux/centos/docker-ce.repo

3)安装Docker CE
 yum install docker-ce -y`
 
4)配置加速器
 curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://bc437cce.m.daocloud.io`
 #因为默认源会去国外获取数据,所以会慢可以超时,这是我们就需要配置加速器指向国内源https://www.daocloud.io/
 
5)启动并开机启动
# systemctl start docker
# systemctl enable docker

四、构建基础镜像

【Apache、Nginx、Tomcat、LNMP、LAMP、LNTP】

JAVA程序必须有JDK环境才可以运行,为了减少镜像大小及提高性能,这里直接把JDK放到宿主机上,容器以挂载形式使用。

1,安装jdk

#rz 把tar包上传,解压后放到指定目录
rz....... 
tar -zxvf jdk-8u60-linux-x64.tar.gz
mv jdk1.8.0_60 /usr/local/jdk1.8

2,拟写Dockerfile

# cat Dockerfile
FROM centos:7
#他的妈妈是谁
MAINTAINER www.aliangedu.com
#他的爸爸是谁
ENV VERSION=8.5.33
#tomcat版本
ENV JAVA_HOME /usr/local/jdk
#jdk 绝对路径
RUN yum install wget -y
#运行的命令
RUN wget http://mirrors.shu.edu.cn/apache/tomcat/tomcat-8/v${VERSION}/bin/apache-tomcat-${VERSION}.tar.gz && 
 tar zxf apache-tomcat-${VERSION}.tar.gz && 
 mv apache-tomcat-${VERSION} /usr/local/tomcat && 
 rm -rf apache-tomcat-${VERSION}.tar.gz /usr/local/tomcat/webapps/* && 
 mkdir /usr/local/tomcat/webapps/ROOT
EXPOSE 8080
#程序使用的端口
CMD /usr/local/tomcat/bin/catalina.sh run
#执行tomcat目录下的启动脚本,这里面遇到坑,就是-v 将宿主机jdk目录挂在到容器/usr/local/jdk 时候,因为镜像按照dockerfile去打,那么在执行命令的时候就会找不到路径,所以我临时删除了,EXPOSE与CMD 2行,然后重新打包,使用 -p 指定端口,然后进入容器,手工启动tomcat的方式,进行

3,构建镜像

docker build -t 192.168.56.11:5000/tomcat-85:latest -f dockerfile . 
#最后这个点。代表当前路径,在制作镜像时,会记录上下文内容

4,上传到docker 镜像仓库

root@node02 scripts]# docker push 192.168.56.11:5000/tomcat-85:latest 

5,启动镜像 测试

[root@node02 scripts]# docker run -it -d -p 8080:8080 -v /usr/local/jdk1.8:/usr/local/jdk 192.168.56.11:5000/tomcat-8:latest
[root@3addff07c464 ROOT]# echo "123" >index.jsp

五、Jenkins 配置

1.主页面 -> 系统管理 -> 全局工具配置

指定JDK、Maven路径,Git保持默认:

2.jenkins安装必要插件

主页面 -> 系统管理 ->管理插件:

安装SSH与Git Parameter插件。

插件说明:

  • 》SSH:用于SSH远程Docker主机执行Shell命令
  • 》Git Parameter:动态获取Git仓库Branch、Tag

3,配置SSH插件

第一步:先创建一个用于连接Docker主机的凭证 (有权限的用户)

主页面 -> 凭据 -> 系统 -> 右击全局凭据 -> 添加凭据:

输入连接Docker主机的用户名和密码:

第二步:添加SSH远程主机

主页面 -> 系统管理 -> 系统设置 -> SSH remote hosts:

问题:当以普通用户身份去使用docker images时,出现以下错误:

六、将从github上下载的JAVA项目,上传到自己的gitlab仓库

# git clone https://github.com/b3log/solo
# cd solo
移除旧的推送地址,添加新的:
# git remote remove origin 
# git remote add origin git@gitlab.example.com:qqq/solo.git
提交代码到Git仓库并创建tag:
# touch src/main/webapp/a.html
# git add .
# git commit -m “a”
创建标签:
# git tag 1.0.0
推送到Git服务器:
# git push origin 1.0.0 

登陆gitlab查看solo项目:

七、Jenkins创建项目并发布测试

1.主页面 -> 新建任务 -> 输入任务名称,构建一个Maven项目:

注意:如果没有显示“构建一个Maven项目”选项,需要在管理插件里安装“Maven Integration plugin”插件。

配置Git参数化构建:

2.动态获取Git仓库tag,与用户交互选择Tag发布:【也可以设置分支】

3.指定项目Git仓库地址:

修改*/master为$Tag,Tag是上面动态获取的变量名,表示根据用户选择打代码版本。

4.设置maven构建命令选项:

clean package -Dmaven.test.skip=ture

利用pom.xml文件构建项目。

在Jenkins本机镜像构建与推送到镜像仓库,并SSH远程连接到Docker主机使用推送的镜像创建容器:

上图中 命令内容如下:

REPOSITORY=192.168.56.11:5000/solo:${Tag}
# 构建镜像
cat > Dockerfile << EOF
FROM 192.168.56.11:5000/tomcat-8:latest
RUN rm -rf /usr/local/tomcat/webapps/ROOT
COPY target/*.war /usr/local/tomcat/webapps/ROOT.war
CMD ["/usr/local/tomcat/bin/catalina.sh", "run"]
EOF
docker build -t $REPOSITORY .
# 上传镜像
docker push $REPOSITORY


上图中Command 内容如下:

REPOSITORY=192.168.56.11:5000/solo:${Tag}
# 部署
sudo docker rm -f blog-solo |true
sudo docker image rm $REPOSITORY |true
sudo docker container run -d --name blog-solo -v /usr/local/jdk1.8:/usr/local/jdk -p 8080:8080 $REPOSITORY
# -d 后台运行 ,-v 挂在目录,-p 映射端口,后面是镜像

注:容器名称blog-solo,暴露宿主机端口8080,即使用宿主机IP 192.168.56.12:8080 访问blog-solo项目。

blog-solo项目已配置完成,开始构建:

选择tag,开始构建:

点击左下角构建历史里,右击第一个查看控制台输出:

构建详细内容

构建成功

访问:192.168.56.12:8080 查看部署结果

调整项目访问地址

进入容器,切换到项目目录

vi WEB-INF/classes/latke.properties 
#### Server ####
# Browser visit protocol
serverScheme=http
# Browser visit domain name
serverHost=192.168.56.12
# Browser visit port, 80 as usual, THIS IS NOT SERVER LISTEN PORT!
serverPort=8080

调整后,重启tomcat,再次验证,OK,结果如下:

至此,自动化CI环境搭建完成,你可以模拟提交代码并打tag测试自动化发布流程。

八、问题总结:

查看docker.sock权限

[root@node03 ~]# ll /var/run/docker.sock 
srw-rw---- 1 root docker 0 9月 4 21:55 /var/run/docker.sock

解决方法:【免sudo 使用docker images 】

[root@node03 ~]# sudo groupadd docker
 ##groupadd:“docker”组已存在
[root@node03 ~]# sudo gpasswd -a jenkins docker
 ##正在将用户“jenkins”加入到“docker”组中
[root@node03 ~]# sudo service docker restart
##重启服务
[root@node03 ~]# newgrp - docker
##重新加载group 组信息,一定要输入这条命令,否则无法加载最新组内容,因为有缓存

原文:https://www.toutiao.com/a6602...

使用 GitLab CI 和 Docker 自动部署 Spring Boot 应用

Docker 常见疑难杂症解决方案

图片

这里主要是为了记录在使用 Docker 的时候遇到的问题及其处理解决方法。

图片

1.Docker 迁移存储目录

默认情况系统会将 Docker 容器存放在/var/lib/docker 目录下

问题起因:今天通过监控系统,发现公司其中一台服务器的磁盘快慢,随即上去看了下,发现 /var/lib/docker 这个目录特别大。由上述原因,我们都知道,在 /var/lib/docker 中存储的都是相关于容器的存储,所以也不能随便的将其删除掉。

那就准备迁移 docker 的存储目录吧,或者对 /var 设备进行扩容来达到相同的目的。更多关于 dockerd 的详细参数,请点击查看 官方文档 地址。

但是需要注意的一点就是,尽量不要用软链, 因为一些 docker 容器编排系统不支持这样做,比如我们所熟知的 k8s 就在内。

# 发现容器启动不了了
ERROR:cannot  create temporary directory!
# 查看系统存储情况
$ du -h --max-depth=1

解决方法1:添加软链接

# 1.停止docker服务
$ sudo systemctl stop docker
# 2.开始迁移目录
$ sudo mv /var/lib/docker /data/
# 3.添加软链接
# sudo ln -s /data/docker /var/lib/docker
# 4.启动docker服务
$ sudo systemctl start docker

解决方法2:改动 docker 配置文件

# 3.改动docker启动配置文件
$ sudo vim /lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --graph=/data/docker/
# 4.改动docker启动配置文件
$ sudo vim /etc/docker/daemon.json
{
    "live-restore": true,
    "graph": [ "/data/docker/" ]
}

操作注意事项:在迁移 docker 目录的时候注意使用的命令,要么使用 mv 命令直接移动,要么使用 cp 命令复制文件,但是需要注意同时复制文件权限和对应属性,不然在使用的时候可能会存在权限问题。如果容器中,也是使用 root 用户,则不会存在该问题,但是也是需要按照正确的操作来迁移目录。

# 使用mv命令
$ sudo mv /var/lib/docker /data/docker
# 使用cp命令
$ sudo cp -arv /data/docker /data2/docker

下图中,就是因为启动的容器使用的是普通用户运行进程的,且在运行当中需要使用 /tmp 目录,结果提示没有权限。在我们导入容器镜像的时候,其实是会将容器启动时需要的各个目录的权限和属性都赋予了。如果我们直接是 cp 命令单纯复制文件内容的话,就会出现属性不一致的情况,同时还会有一定的安全问题。

图片

2.Docker 设备空间不足

Increase Docker container size from default 10GB on rhel7.

问题起因一:容器在导入或者启动的时候,如果提示磁盘空间不足的,那么多半是真的因为物理磁盘空间真的有问题导致的。如下所示,我们可以看到 / 分区确实满了。

# 查看物理磁盘空间
$ df -Th
Filesystem    Size    Used    Avail    Use%    Mounted on
/dev/vda1      40G     40G       0G    100%    /
tmpfs         7.8G       0     7.8G      0%    /dev/shm
/dev/vdb1     493G    289G     179G     62%    /mnt

如果发现真的是物理磁盘空间满了的话,就需要查看到底是什么占据了如此大的空间,导致因为容器没有空间无法启动。其中,docker 自带的命令就是一个很好的能够帮助我们发现问题的工具。

# 查看基本信息
# 硬件驱动使用的是devicemapper,空间池为docker-252
# 磁盘可用容量仅剩16.78MB,可用供我们使用
$ docker info
Containers: 1
Images: 28
Storage Driver: devicemapper
 Pool Name: docker-252:1-787932-pool
 Pool Blocksize: 65.54 kB
 Backing Filesystem: extfs
 Data file: /dev/loop0
 Metadata file: /dev/loop1
 Data Space Used: 1.225 GB
 Data Space Total: 107.4 GB
 Data Space Available: 16.78 MB
 Metadata Space Used: 2.073 MB
 Metadata Space Total: 2.147 GB

解决方法:通过查看信息,我们知道正是因为 docker 可用的磁盘空间不足,所以导致启动的时候没有足够的空间进行加载启动镜像。解决的方法也很简单,第一就是清理无效数据文件释放磁盘空间(清除日志),第二就是修改 docker 数据的存放路径(大分区)。

# 显示哪些容器目录具有最大的日志文件
$ du -d1 -h /var/lib/docker/containers | sort -h
# 清除您选择的容器日志文件的内容
$ cat /dev/null > /var/lib/docker/containers/container_id/container_log_name

问题起因二:显然我遇到的不是上一种情况,而是在启动容器的时候,容器启动之后不久就显示是 unhealthy 的状态,通过如下日志发现,原来是复制配置文件启动的时候,提示磁盘空间不足。

后面发现是因为 CentOS7 的系统使用的 docker 容器默认的创建大小就是 10G 而已,然而我们使用的容器却超过了这个限制,导致无法启动时提示空间不足。

2019-08-16 11:11:15,816 INFO spawned: 'app-demo' with pid 835
2019-08-16 11:11:16,268 INFO exited: app (exit status 1; not expected)
2019-08-16 11:11:17,270 INFO gave up: app entered FATAL state, too many start retries too quickly
cp: cannot create regular file '/etc/supervisor/conf.d/grpc-app-demo.conf': No space left on device
cp: cannot create regular file '/etc/supervisor/conf.d/grpc-app-demo.conf': No space left on device
cp: cannot create regular file '/etc/supervisor/conf.d/grpc-app-demo.conf': No space left on device
cp: cannot create regular file '/etc/supervisor/conf.d/grpc-app-demo.conf': No space left on device

解决方法1:改动 docker 启动配置文件

# /etc/docker/daemon.json
{
    "live-restore": true,
    "storage-opt": [ "dm.basesize=20G" ]
}

解决方法2:改动 systemctl 的 docker 启动文件

# 1.stop the docker service
$ sudo systemctl stop docker
# 2.rm exised container
$ sudo rm -rf /var/lib/docker
# 2.edit your docker service file
$ sudo vim /usr/lib/systemd/system/docker.service
# 3.find the execution line
ExecStart=/usr/bin/dockerd
and change it to:
ExecStart=/usr/bin/dockerd --storage-opt dm.basesize=20G
# 4.start docker service again
$ sudo systemctl start docker
# 5.reload daemon
$ sudo systemctl daemon-reload

问题起因三:还有一种情况也会让容器无法启动,并提示磁盘空间不足,但是使用命令查看发现并不是因为物理磁盘真的不足导致的。而是,因为对于分区的 inode 节点数满了导致的。

# 报错信息
No space left on device

解决方法:因为 ext3 文件系统使用 inode table 存储 inode 信息,而 xfs 文件系统使用 B+ tree 来进行存储。考虑到性能问题,默认情况下这个 B+ tree 只会使用前 1TB 空间,当这 1TB 空间被写满后,就会导致无法写入 inode 信息,报磁盘空间不足的错误。我们可以在 mount 时,指定 inode64 即可将这个 B+ tree 使用的空间扩展到整个文件系统。

# 查看系统的inode节点使用情况
$ sudo df -i
# 尝试重新挂载
$ sudo mount -o remount -o noatime,nodiratime,inode64,nobarrier /dev/vda1

补充知识:文件储存在硬盘上,硬盘的最小存储单位叫做“扇区”(Sector)。每个扇区储存 512 字节(相当于0.5KB)。操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个“块”(block)。这种由多个扇区组成的”块”,是文件存取的最小单位。”块”的大小,最常见的是4KB,即连续八个 sector 组成一个 block 块。文件数据都储存在”块”中,那么很显然,我们还必须找到一个地方储存文件的元信息,比如文件的创建者、文件的创建日期、文件的大小等等。这种储存文件元信息的区域就叫做“索引节点”(inode)。每一个文件都有对应的 inode,里面包含了除了文件名以外的所有文件信息。

inode 也会消耗硬盘空间,所以硬盘格式化的时候,操作系统自动将硬盘分成两个区域。一个是数据区,存放文件数据;另一个是 inode 区(inode table),存放 inode 所包含的信息。每个 inode 节点的大小,一般是 128 字节或 256 字节。inode 节点的总数,在格式化时就给定,一般是每1KB或每2KB就设置一个 inode 节点。

# 每个节点信息的内容
$ stat check_port_live.sh
  File: check_port_live.sh
  Size: 225           Blocks: 8          IO Block: 4096   regular file
Device: 822h/2082d    Inode: 99621663    Links: 1
Access: (0755/-rwxr-xr-x)  Uid: ( 1006/  escape)   Gid: ( 1006/  escape)
Access: 2019-07-29 14:59:59.498076903 +0800
Modify: 2019-07-29 14:59:59.498076903 +0800
Change: 2019-07-29 23:20:27.834866649 +0800
 Birth: -
# 磁盘的inode使用情况
$ df -i
Filesystem                 Inodes   IUsed     IFree IUse% Mounted on
udev                     16478355     801  16477554    1% /dev
tmpfs                    16487639    2521  16485118    1% /run
/dev/sdc2               244162560 4788436 239374124    2% /
tmpfs                    16487639       5  16487634    1% /dev/shm

3.Docker 缺共享链接库

Docker 命令需要对/tmp 目录下面有访问权限

问题起因:给系统安装完 compose 之后,查看版本的时候,提示缺少一个名为 libz.so.1 的共享链接库。第一反应就是,是不是系统少安装那个软件包导致的。随即,搜索了一下,将相关的依赖包都给安装了,却还是提示同样的问题。

# 提示错误信息
$ docker-compose --version
error while loading shared libraries: libz.so.1: failed to map segment from shared object: Operation not permitted

解决方法:后来发现,是因为系统中 docker 没有对 /tmp 目录的访问权限导致,需要重新将其挂载一次,就可以解决了。

# 重新挂载
$ sudo mount /tmp -o remount,exec

4.Docker 容器文件损坏

对 dockerd 的配置有可能会影响到系统稳定

问题起因:容器文件损坏,经常会导致容器无法操作。正常的 docker 命令已经无法操控这台容器了,无法关闭、重启、删除。正巧,前天就需要这个的问题,主要的原因是因为重新对 docker 的默认容器进行了重新的分配限制导致的。

# 操作容器遇到类似的错误
b'devicemapper: Error running deviceCreate (CreateSnapDeviceRaw) dm_task_run failed'

解决方法:可以通过以下操作将容器删除/重建。

# 1.关闭docker
$ sudo systemctl stop docker
# 2.删除容器文件
$ sudo rm -rf /var/lib/docker/containers
# 3.重新整理容器元数据
$ sudo thin_check /var/lib/docker/devicemapper/devicemapper/metadata
$ sudo thin_check --clear-needs-check-flag /var/lib/docker/devicemapper/devicemapper/metadata
# 4.重启docker
$ sudo systemctl start docker

5.Docker 容器优雅重启

不停止服务器上面运行的容器,重启 dockerd 服务是多么好的一件事

问题起因:默认情况下,当 Docker 守护程序终止时,它会关闭正在运行的容器。从 Docker-ce 1.12 开始,可以在配置文件中添加 live-restore 参数,以便在守护程序变得不可用时容器保持运行。需要注意的是 Windows 平台暂时还是不支持该参数的配置。

# Keep containers alive during daemon downtime
$ sudo vim /etc/docker/daemon.yaml
{
  "live-restore": true
}
# 在守护进程停机期间保持容器存活
$ sudo dockerd --live-restore
# 只能使用reload重载
# 相当于发送SIGHUP信号量给dockerd守护进程
$ sudo systemctl reload docker
# 但是对应网络的设置需要restart才能生效
$ sudo systemctl restart docker

解决方法:可以通过以下操作将容器删除/重建。

# /etc/docker/daemon.yaml
{
    "registry-mirrors": ["https://vec0xydj.mirror.aliyuncs.com"],  # 配置获取官方镜像的仓库地址
    "experimental": true,  # 启用实验功能
    "default-runtime": "nvidia",  # 容器的默认OCI运行时(默认为runc)
    "live-restore": true,  # 重启dockerd服务的时候容易不终止
    "runtimes": {  # 配置容器运行时
        "nvidia": {
            "path": "/usr/bin/nvidia-container-runtime",
            "runtimeArgs": []
        }
    },
    "default-address-pools": [  # 配置容器使用的子网地址池
        {
            "scope": "local",
            "base":"172.17.0.0/12",
            "size":24
        }
    ]
}

6.Docker 容器无法删除

找不到对应容器进程是最吓人的

问题起因:今天遇到 docker 容器无法停止/终止/删除,以为这个容器可能又出现了 dockerd 守护进程托管的情况,但是通过ps -ef <container id>无法查到对应的运行进程。哎,后来开始开始查 supervisor 以及 Dockerfile 中的进程,都没有。这种情况的可能原因是容器启动之后,之后,主机因任何原因重新启动并且没有优雅地终止容器。剩下的文件现在阻止你重新生成旧名称的新容器,因为系统认为旧容器仍然存在。

# 删除容器
$ sudo docker rm -f f8e8c3..
Error response from daemon: Conflict, cannot remove the default name of the container

解决方法:找到 /var/lib/docker/containers/ 下的对应容器的文件夹,将其删除,然后重启一下 dockerd 即可。我们会发现,之前无法删除的容器没有了。

# 删除容器文件
$ sudo rm -rf /var/lib/docker/containers/f8e8c3...65720
# 重启服务
$ sudo systemctl restart docker.service

7.Docker 容器中文异常

容器存在问题话,记得优先在官网查询

问题起因:今天登陆之前部署的 MySQL 数据库查询,发现使用 SQL 语句无法查询中文字段,即使直接输入中文都没有办法显示。

# 查看容器支持的字符集
root@b18f56aa1e15:# locale -a
C
C.UTF-8
POSIX

解决方法:Docker 部署的 MySQL 系统使用的是 POSIX 字符集。然而 POSIX 字符集是不支持中文的,而 C.UTF-8 是支持中文的只要把系统中的环境 LANG 改为 "C.UTF-8" 格式即可解决问题。同理,在 K8S 进入 pod 不能输入中文也可用此方法解决。

# 临时解决
docker exec -it some-mysql env LANG=C.UTF-8 /bin/bash
# 永久解决
docker run --name some-mysql 
    -e MYSQL_ROOT_PASSWORD=my-secret-pw 
    -d mysql:tag --character-set-server=utf8mb4 
    --collation-server=utf8mb4_unicode_ci

8.Docker 容器网络互通

了解 Docker 的四种网络模型

问题起因:在本机部署 Nginx 容器想代理本机启动的 Python 后端服务程序,但是对代码服务如下的配置,结果访问的时候一直提示 502 错误。

# 启动Nginx服务
$ docker run -d -p 80:80 $PWD:/etc/nginx nginx
nginx
server {
    ...
    location /api {
        proxy_pass http://localhost:8080
    }
    ...
}

解决方法:后面发现是因为 nginx.conf 配置文件中的 localhost 配置的有问题,由于 Nginx 是在容器中运行,所以 localhost 为容器中的 localhost,而非本机的 localhost,所以导致无法访问。

可以将 nginx.conf 中的 localhost 改为宿主机的 IP 地址,就可以解决 502 的错误。

# 查询宿主机IP地址 => 172.17.0.1
$ ip addr show docker0
docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:d5:4c:f2:1e brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:d5ff:fe4c:f21e/64 scope link
       valid_lft forever preferred_lft forever
nginx
server {
    ...
    location /api {
        proxy_pass http://172.17.0.1:8080
    }
    ...
}

当容器使用 host 网络时,容器与宿主共用网络,这样就能在容器中访问宿主机网络,那么容器的 localhost 就是宿主机的 localhost 了。

# 服务的启动方式有所改变(没有映射出来端口)
# 因为本身与宿主机共用了网络,宿主机暴露端口等同于容器中暴露端口
$ docker run -d -p 80:80 --network=host $PWD:/etc/nginx nginxx

9.Docker 容器总线错误

总线错误看到的时候还是挺吓人了

问题起因:在 docker 容器中运行程序的时候,提示 bus error 错误。

# 总线报错
$ inv app.user_op --name=zhangsan
Bus error (core dumped)

解决方法:原因是在 docker 运行的时候,shm 分区设置太小导致 share memory 不够。不设置 –shm-size 参数时,docker 给容器默认分配的 shm 大小为 64M,导致程序启动时不足。

# 启动docker的时候加上--shm-size参数(单位为b,k,m或g)
$ docker run -it --rm --shm-size=200m pytorch/pytorch:latest

解决方法:还有一种情况就是容器内的磁盘空间不足,也会导致 bus error 的报错,所以清除多余文件或者目录,就可以解决了。

# 磁盘空间不足
$ df -Th
Filesystem     Type     Size  Used Avail Use% Mounted on
overlay        overlay    1T    1T    0G 100% /
shm            tmpfs     64M   24K   64M   1% /dev/shm

10.Docker NFS 挂载报错

总线错误看到的时候还是挺吓人了

问题起因:我们将服务部署到 openshift 集群中,启动服务调用资源文件的时候,报错信息如下所示。从报错信息中,得知是在 Python3 程序执行 read_file() 读取文件的内容,给文件加锁的时候报错了。但是奇怪的是,本地调试的时候发现服务都是可以正常运行的,文件加锁也是没问题的。后来发现,在 openshift 集群中使用的是 NFS 挂  载的共享磁盘。

# 报错信息
Traceback (most recent call last):
    ......
    File "xxx/utils/storage.py", line 34, in xxx.utils.storage.LocalStorage.read_file
OSError: [Errno 9] Bad file descriptor
# 文件加锁代码
...
    with open(self.mount(path), 'rb') as fileobj:
        fcntl.flock(fileobj, fcntl.LOCK_EX)
        data = fileobj.read()
    return data
...

解决方法:从下面的信息得知,要在 Linux 中使用 flock() 的话,就需要升级内核版本到 2.6.11+ 才行。后来才发现,这实际上是由 RedHat 內核中的一个错误引起的,并在 kernel-3.10.0-693.18.1.el7 版本中得到修复。所以对于 NFSv3 和 NFSv4 服务而已,就需要升级 Linux 内核版本才能够解决这个问题。

# https://t.codebug.vip/questions-930901.htm
$ In Linux kernels up to 2.6.11, flock() does not lock files over NFS (i.e.,
the scope of locks was limited to the local system). [...] Since Linux 2.6.12,
NFS clients support flock() locks by emulating them as byte-range locks on the entire file.

11.Docker 默认使用网段


启动的容器网络无法相互通信,很是奇怪!

问题起因:我们在使用 Docker 启动服务的时候,发现有时候服务之前可以相互连通,而有时间启动的多个服务之前却出现了无法访问的情况。究其原因,发现原来是因为使用的内部私有地址网段不一致导致的。有点服务启动到了 172.17 - 172.31 的网段,有的服务跑到了 192.169.0 - 192.168.224 的网段,这样导致服务启动之后出现无法访问的情况。

image.png

解决方法:上述问题的处理方式,就是手动指定 Docker 服务的启动网段,就可以了。

# 查看docker容器配置
$ cat /etc/docker/daemon.json
{
    "registry-mirrors": ["https://vec0xydj.mirror.aliyuncs.com"],
    "default-address-pools":[{"base":"172.17.0.0/12","size":24}],
    "experimental": true,
    "default-runtime": "nvidia",
    "live-restore": true,
    "runtimes": {
        "nvidia": {
            "path": "/usr/bin/nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
}

12.Docker 服务启动串台


使用 docker-compose 命令各自启动两组服务,发现服务会串台!

问题起因:在两个不同名称的目录目录下面,使用 docker-compose 来启动服务,发现当 A 组服务启动完毕之后,再启动 B 组服务的时候,发现 A 组当中对应的一部分服务又重新启动了一次,这就非常奇怪了!因为这个问题的存在会导致,A 组服务和 B 组服务无法同时启动。之前还以为是工具的 Bug,后来请教了“上峰”,才知道了原因,恍然大悟。

# 服务目录结构如下所示
A: /data1/app/docker-compose.yml
B: /data2/app/docker-compose.yml

解决方法:发现 A 和 B 两组服务会串台的原因,原来是 docker-compose 会给启动的容器加 label 标签,然后根据这些 label 标签来识别和判断对应的容器服务是由谁启动的、谁来管理的,等等。而这里,我们需要关注的 label 变量是 com.docker.compose.project,其对应的值是使用启动配置文件的目录的最底层子目录名称,即上面的 app 就是对应的值。我们可以发现, A 和 B 两组服务对应的值都是 app,所以启动的时候被认为是同一个,这就出现了上述的问题。如果需要深入了解的话,可以去看对应源代码。

图片

# 可以将目录结构调整为如下所示
A: /data/app1/docker-compose.yml
B: /data/app2/docker-compose.yml
A: /data1/app-old/docker-compose.yml
B: /data2/app-new/docker-compose.yml

或者使用 docker-compose 命令提供的参数 -p 来规避该问题的发生。

# 指定项目项目名称
$ docker-compose -f ./docker-compose.yml -p app1 up -d

13.Docker 命令调用报错


在编写脚本的时候常常会执行 docker 相关的命令,但是需要注意使用细节!

问题起因:CI 更新环境执行了一个脚本,但是脚本执行过程中报错了,如下所示。通过对应的输出信息,可以看到提示说正在执行的设备不是一个 tty。

图片

随即,查看了脚本发现报错地方是执行了一个 exec 的 docker 命令,大致如下所示。很奇怪的是,手动执行或直接调脚本的时候,怎么都是没有问题的,但是等到 CI 调用的时候怎么都是有问题。后来好好看下下面这个命令,注意到 -it 这个参数了。

# 脚本调用docker命令
docker exec -it <container_name> psql -Upostgres ......
我们可以一起看下 exec 命令的这两个参数,自然就差不多理解了。
-i/-interactive #即使没有附加也保持 STDIN 打开;如果你需要执行命令则需要开启这个选项
-t/–tty #分配一个伪终端进行执行;一个连接用户的终端与容器 stdin 和 stdout 的桥梁

解决方法:docker exec 的参数 -t 是指 Allocate a pseudo-TTY 的意思,而 CI 在执行 job 的时候并不是在 TTY 终端中执行,所以 -t 这个参数会报错。

图片

14.Docker 定时任务异常


在 Crontab 定时任务中也存在 Docker 命令执行异常的情况!

问题起因:今天发现了一个问题,就是在备份 Mysql 数据库的时候,使用 docker 容器进行备份,然后使用 Crontab 定时任务来触发备份。但是发现备份的 MySQL 数据库居然是空的,但是手动执行对应命令切是好的,很奇怪。

# Crontab定时任务
0 */6 * * * 
    docker exec -it <container_name> sh -c 
        'exec mysqldump --all-databases -uroot -ppassword ......'

解决方法:后来发现是因为执行的 docker 命令多个 -i 导致的。因为 Crontab 命令执行的时候,并不是交互式的,所以需要把这个去掉才可以。总结就是,如果你需要回显的话则需要 -t 选项,如果需要交互式会话则需要 -i 选项。

-i/-interactive #即使没有附加也保持 STDIN 打开;如果你需要执行命令则需要开启这个选项
-t/–tty  #分配一个伪终端进行执行;一个连接用户的终端与容器 stdin 和 stdout 的桥梁

15.Docker 变量使用引号


compose 里边环境变量带不带引号的问题!

问题起因:使用过 compose 的同学可能都遇到过,我们在编写启动配置文件的时候,添加环境变量的时候到底是使用单引号、双引号还是不使用引号。时间长了,可能我们总是三者是一样的,可以相互使用。但是,直到最后我们发现坑越来越多,越来越隐晦。

反正我是遇到过很多是因为添加引号导致的服务启动问题,后来得出的结论就是一律不适用引号。裸奔,体验前所未有的爽快!直到现在看到了 Github 中对应的 issus 之后,才终于破案了。

# TESTVAR="test"
在Compose中进行引用TESTVAR变量,无法找到
# TESTVAR=test
在Compose中进行引用TESTVAR变量,可以找到
# docker run -it --rm -e TESTVAR="test" test:latest
后来发现docker本身其实已经正确地处理了引号的使用

解决方法:得到的结论就是,因为 Compose 解析 yaml 配置文件,发现引号也进行了解释包装。这就导致原本的 TESTVAR="test" 被解析成了 'TESTVAR="test"',所以我们在引用的时候就无法获取到对应的值。现在解决方法就是,不管是我们直接在配置文件添加环境变量或者使用 env_file 配置文件,能不使用引号就不适用引号。

16. Docker 删除镜像报错


无法删除镜像,归根到底还是有地方用到了!

问题起因:清理服器磁盘空间的时候,删除某个镜像的时候提示如下信息。提示需要强制删除,但是发现及时执行了强制删除依旧没有效果。

# 删除镜像
$ docker rmi 3ccxxxx2e862
Error response from daemon: conflict: unable to delete 3ccxxxx2e862 (cannot be forced) - image has dependent child images
# 强制删除
$ dcoker rmi -f 3ccxxxx2e862
Error response from daemon: conflict: unable to delete 3ccxxxx2e862 (cannot be forced) - image has dependent child images

解决方法:后来才发现,出现这个原因主要是因为 TAG,即存在其他镜像引用了这个镜像。这里我们可以使用如下命令查看对应镜像文件的依赖关系,然后根据对应 TAG 来删除镜像。

# 查询依赖 - image_id表示镜像名称
$ docker image inspect --format='{{.RepoTags}} {{.Id}} {{.Parent}}' $(docker image ls -q --filter since=<image_id>)
# 根据TAG删除镜像
$ docker rmi -f c565xxxxc87f
bash
# 删除悬空镜像
$ docker rmi $(docker images --filter "dangling=true" -q --no-trunc)

17.Docker 普通用户切换


切换 Docker 启动用户的话,还是需要注意下权限问题的!

问题起因:我们都知道在 Docker 容器里面使用 root 用户的话,是不安全的,很容易出现越权的安全问题,所以一般情况下,我们都会使用普通用户来代替 root 进行服务的启动和管理的。今天给一个服务切换用户的时候,发现 Nginx 服务一直无法启动,提示如下权限问题。因为对应的配置文件也没有配置 var 相关的目录,无奈 🤷‍♀ !️

# Nginx报错信息
nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (13: Permission denied)
2020/11/12 15:25:47 [emerg] 23#23: mkdir() "/var/cache/nginx/client_temp" failed (13: Permission denied)

解决方法:后来发现还是 nginx.conf 配置文件,配置的有问题,需要将 Nginx 服务启动时候需要的文件都配置到一个无权限的目录,即可解决。

nginx
user  www-data;
worker_processes  1;
error_log  /data/logs/master_error.log warn;
pid        /dev/shm/nginx.pid;
events {
    worker_connections  1024;
}
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    gzip               on;
    sendfile           on;
    tcp_nopush         on;
    keepalive_timeout  65;
    client_body_temp_path  /tmp/client_body;
    fastcgi_temp_path      /tmp/fastcgi_temp;
    proxy_temp_path        /tmp/proxy_temp;
    scgi_temp_path         /tmp/scgi_temp;
    uwsgi_temp_path        /tmp/uwsgi_temp;
    include /etc/nginx/conf.d/*.conf;
}

史上最全、最详细的Docker学习资料  推荐给你看一看。

新手学习项目

推荐给大家:推荐 11 个极易上手的 Docker 实践项目

定期更新的Docker学习文章

查看原文

赞 8 收藏 7 评论 0

民工哥 发布了文章 · 4月16日

每天学一个 Linux 命令(116):cfdisk

命令简介

cfdisk 命令可用于显示有关磁盘分区表的信息。它的功能与 fdisk相同,但它具有基于文本的“图形”界面,在操作与可视化方面更加的直观,易于使用,也非常的便捷。

图片

上面就是cfdisk的图形化界面

语法格式

cfdisk [-agvz] [-c cylinders] [-h heads] [-s sectors-per-track]  [-P opt] [device]

选项说明

-a #使用箭头光标突出显示当前分区
-g #不要使用磁盘驱动程序给出的几何图形
-v #打印版本号和版权
-z #从零位分区表开始
-s sectors-per-track   #覆盖从BIOS读取的每个磁道的柱面数,磁头数和扇区数。

应用举例

直接输入cfdisk命令进入图形界面图片

按上下箭头键选择磁盘名字图片

查看帮助信息图片

基本的使用与fdisk一样,磁盘新建分区图片

选择分区类型图片

选择分区大小图片

操作写入磁盘图片

基本的操作就是这样,非常简单。

每天学一个 Linux 命令(113):dnf

每天学一个 Linux 命令(114):ldd

每天学一个 Linux 命令(115):accton

查看原文

赞 1 收藏 1 评论 0

民工哥 发布了文章 · 4月16日

每天学一个 Linux 命令(117):atop

命令简介

atop 命令是一款监控 Linux 系统资源与进程的工具,非内部命令,需要安装。

[root@centos7 ~]# atop
-bash: atop: command not found
[root@centos7 ~]# yum install atop -y

#Debian && Ubuntu
apt-get install atop

#Fedora
dnf install atop

atop 是以一定的频率记录系统的运行状态,所采集的数据包含系统资源(CPU、内存、磁盘和网络)使用情况和进程运行情况,并能以日志文件的方式保存在磁盘中,服务器出现问题后,我们可获取相应的atop日志文件进行分析,atop是一款开源软件。

语法格式

atop -w  file  [-S] [-a] [interval [samples]]
atop -r [file] [-b [YYYYMMDD]hhmm] [-e [YYYYMMDD]hhmm] [-flags]

选项说明

进程图的快捷键

g  #默认输出
m  #内存相关输出
d  #磁盘相关输出
n  #网络相关输出
c  #命令行输出
u  #查看对应的用户资源使用情况
p  #显示所有每个进程的所有信息占用情况(disk、mem、io)
P(大写) #正则匹配,显示所有匹配到的进程
q  #退出

应用举例

[root@centos7 ~]# atop
ATOP - centos7              2021/03/29  08:33:28              ----------------              10s elapsed
PRC |  sys    0.18s |  user   0.35s  | #proc     95  |  #tslpu     0 |  #zombie    0  | #exit       0  |
CPU |  sys     1% |  user     3%  | irq     0%  |  idle     96% |  wait      0%  | ipc notavail  |
CPL |  avg1    0.27 |  avg5    0.13  | avg15   0.13  |  csw     1088 |  intr     954  | numcpu     1  |
MEM |  tot   972.3M |  free  203.3M  | cache 563.1M  |  buff    2.1M |  slab   83.8M  | hptot   0.0M  |
SWP |  tot     2.0G |  free    2.0G  | swcac   0.0M  |               |  vmcom 266.0M  | vmlim   2.5G  |
NET |  transport    |  tcpi      1  | tcpo       1  |  udpi       1 |  udpo       1  | tcpao      0  |
NET |  network      |  ipi      17  | ipo       3  |  ipfrw       0 |  deliv     17  | icmpo      1  |
NET |  ens33   ---- |  pcki     20  | pcko       5  |  sp    0 Mbps |  si    6 Kbps  | so    1 Kbps  |

   PID SYSCPU  USRCPU RDELAY   VGROW  RGROW   RDDSK  WRDSK  ST  EXC  THR  S CPUNR   CPU CMD         1/1
 18378  0.08s   0.33s  0.11s      0K     0K      0K     0K  --    -    3  S     0    4% python3
 27620  0.04s   0.02s  0.00s      0K     0K     0K     0K  --    -    1  R     0    1% atop
 27664  0.04s   0.00s  0.02s      0K     0K     0K     0K  --    -    1  S     0    0% kworker/0:1
   404  0.02s   0.00s  0.05s      0K     0K      0K     0K  --    -    1  R     0    0% xfsaild/dm-0
   872  0.00s   0.00s  0.00s      0K     0K      0K     0K  --    -    5  S     0    0% tuned
 19670  0.00s   0.00s  0.00s      0K     0K      0K     0K  --    -    1  S     0    0% sshd
   870  0.00s   0.00s  0.00s      0K     0K      0K     0K  --    -    3  S     0    0% rsyslogd
     1  0.00s   0.00s  0.00s      0K     0K     0K     0K  --    -    1  S     0    0% systemd
     6  0.00s   0.00s  0.09s      0K     0K     0K     0K  --    -    1  S     0    0% ksoftirqd/0
     9  0.00s   0.00s  0.29s      0K     0K     0K     0K  --    -    1  R     0    0% rcu_sched
 26820  0.00s   0.00s  0.00s      0K     0K     0K     0K  --    -    1  S     0    0% kworker/0:2
输出信息的详细说明如下
ATOP列:该列显示了主机名、信息采样日期和时间点

PRC列:该列显示进程整体运行情况
sys、usr字段  #进程在内核态和用户态的运行时间
proc字段      #进程总数
zombie字段    #僵死进程的数量
exit字段      #atop采样周期期间退出的进程数量

CPU列:该列显示CPU整体(即多核CPU作为一个整体CPU资源)的使用情况

sys、usr字段   #CPU被用于处理进程时,进程在内核态、用户态所占CPU的时间比例
irq字段   #CPU被用于处理中断的时间比例
idle字段  #CPU处在完全空闲状态的时间比例
wait字段  #CPU处在“进程等待磁盘IO导致CPU空闲”状态的时间比例

cpu列:该列显示某一核cpu的使用情况

CPL列:该列显示CPU负载情况
avg1、avg5和avg15字段  #过去1分钟、5分钟和15分钟内运行队列中的平均进程数量
csw字段   #上下文交换次数
intr字段  #中断发生次数

MEM列:该列显示内存的使用情况
tot字段    #物理内存总量
free字段   #空闲内存的大小
cache字段  #用于页缓存的内存大小
buff字段   #用于文件缓存的内存大小
slab字段   #系统内核占用的内存大小

SWP列:该列显示交换空间的使用情况
tot字段   #交换区总量
free字段  #空闲交换空间大小

PAG列:该列显示虚拟内存分页情况
swin、swout字段  #换入和换出内存页数

DSK列:该列显示磁盘使用情况
sda字段   #磁盘设备标识
busy字段  #磁盘忙时比例
read、write字段  #读、写请求数量


NET列:显示网络状况,包括传输层(TCP和UDP)、IP层以及各活动的网口信息

XXXi 字段  #各层或活动网口收包数目
XXXo 字段  #各层或活动网口发包数目

查看原文

赞 1 收藏 1 评论 0

民工哥 发布了文章 · 4月15日

建议收藏!看完全面掌握,最详细的Redis总结(2021最新版)

Redis简介

Redis 是一个使用 C 语言编写的,开源的(BSD许可)高性能非关系型(NoSQL)的键值对数据库。

Redis 可以存储键和五种不同类型的值之间的映射。键的类型只能为字符串,值支持五种数据类型:字符串、列表、集合、散列表、有序集合。

与传统数据库不同的是 Redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。另外,Redis 也经常用来做分布式锁。除此之外,Redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案(Redis 6.0 集群搭建实践)。

从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。

Redis的优缺点

优点

  • 读写性能优异, Redis能读的速度是110000次/s,写的速度是81000次/s。
  • 支持数据持久化,支持AOF和RDB两种持久化方式。
  • 支持事务,Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。
  • 数据结构丰富,除了支持string类型的value外还支持hash、set、zset、list等数据结构。
  • 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。

缺点

  • 数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。
  • Redis 不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。
  • 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。
  • Redis 较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。为避免这一问题,运维人员在系统上线时必须确保有足够的空间,这对资源造成了很大的浪费。

数据类型

Redis主要有5种数据类型,包括String,List,Set,Zset,Hash,满足大部分的使用要求。详细的可参考:Redis 的 8 大数据类型,写得非常好!

使用场景

由于Redis优异的读写性能,持久化支持等优势,Redis的使用场景非常多,主要包括计数器,缓存,消息队列,分布式锁等,具体使用场景如下:

  • 计数器

    • 可以对 String 进行自增自减运算,从而实现计数器功能。
    • Redis 这种内存型数据库的读写性能非常高,很适合存储频繁读写的计数量。
  • 缓存

    • 将热点数据放到内存中,设置内存的最大使用量以及淘汰策略来保证缓存的命中率。
  • 会话缓存

    • 可以使用 Redis 来统一存储多台应用服务器的会话信息。
    • 当应用服务器不再存储用户的会话信息,也就不再具有状态,一个用户可以请求任意一个应用服务器,从而更容易实现高可用性以及可伸缩性。
  • 全页缓存(FPC)

    • 除基本的会话token之外,Redis还提供很简便的FPC平台。
    • 以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。
  • 查找表

    • 例如 DNS 记录就很适合使用 Redis 进行存储。
    • 查找表和缓存类似,也是利用了 Redis 快速的查找特性。但是查找表的内容不能失效,而缓存的内容可以失效,因为缓存不作为可靠的数据来源。
  • 消息队列(发布/订阅功能)

    • List 是一个双向链表,可以通过 lpush 和 rpop 写入和读取消息
    • 不过最好使用 Kafka、RabbitMQ 等消息中间件。
  • 分布式锁实现

    • 在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。
    • 可以使用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。
  • 其它

    • Set 可以实现交集、并集等操作,从而实现共同好友等功能。
    • ZSet 可以实现有序性操作,从而实现排行榜等功能。

持久化

Redis 是内存型数据库,为了之后重用数据(比如重启机器、机器故障之后回复数据),或者是为了防止系统故障而将数据备份到一个远程位置,需要将内存中的数据持久化到硬盘上。

Redis 提供了RDB和AOF两种持久化方式。默认是只开启RDB,当Redis重启时,它会优先使用AOF文件来还原数据集。

Redis持久化详解可以参考:Redis持久化

过期键的删除策略

Redis中有个设置时间过期的功能,即对存储在 redis 数据库中的值可以设置一个过期时间。作为一个缓存数据库,这是非常实用的。如我们一般项目中的 token 或者一些登录信息,尤其是短信验证码都是有时间限制的,按照传统的数据库处理方式,一般都是自己判断过期,这样无疑会严重影响项目性能。

Redis有三种不同的删除策略:立即删除,惰性删除,定时删除

  • (1):立即删除。在设置键的过期时间时,创建一个回调事件,当过期时间达到时,由时间处理器自动执行键的删除操作。
  • (2):惰性删除。键过期了就过期了,不管。每次从dict字典中按key取值时,先检查此key是否已经过期,如果过期了就删除它,并返回nil,如果没过期,就返回键值。
  • (3):定时删除。每隔一段时间,对expires字典进行检查,删除里面的过期键。

可以看到,第二种为被动删除,第一种和第三种为主动删除,且第一种实时性更高。下面对这三种删除策略进行具体分析。

  • 立即删除

立即删除能保证内存中数据的最大新鲜度,因为它保证过期键值会在过期后马上被删除,其所占用的内存也会随之释放。但是立即删除对cpu是最不友好的。因为删除操作会占用cpu的时间,如果刚好碰上了cpu很忙的时候,比如正在做交集或排序等计算的时候,就会给cpu造成额外的压力。

而且目前redis事件处理器对时间事件的处理方式–无序链表,查找一个key的时间复杂度为O(n),所以并不适合用来处理大量的时间事件。

  • 惰性删除

惰性删除是指,某个键值过期后,此键值不会马上被删除,而是等到下次被使用的时候,才会被检查到过期,此时才能得到删除。所以惰性删除的缺点很明显:浪费内存。dict字典和expires字典都要保存这个键值的信息。

举个例子,对于一些按时间点来更新的数据,比如log日志,过期后在很长的一段时间内可能都得不到访问,这样在这段时间内就要拜拜浪费这么多内存来存log。这对于性能非常依赖于内存大小的redis来说,是比较致命的。

  • 定时删除

从上面分析来看,立即删除会短时间内占用大量cpu,惰性删除会在一段时间内浪费内存,所以定时删除是一个折中的办法。

定时删除是:每隔一段时间执行一次删除操作,并通过限制删除操作执行的时长和频率,来减少删除操作对cpu的影响。另一方面定时删除也有效的减少了因惰性删除带来的内存浪费。

  • Redis使用的策略

redis使用的过期键值删除策略是:惰性删除加上定期删除,两者配合使用。

数据淘汰策略

可以设置内存最大使用量,当内存使用量超出时,会施行数据淘汰策略。

Redis 具体有 6 种淘汰策略:

作为内存数据库,出于对性能和内存消耗的考虑,Redis 的淘汰算法实际实现上并非针对所有 key,而是抽样一小部分并且从中选出被淘汰的 key。

Redis 4.0 引入了 volatile-lfu 和 allkeys-lfu 淘汰策略,LFU 策略通过统计访问频率,将访问频率最少的键值对淘汰。

您需要根据系统的特征,来选择合适的淘汰策略。 当然,在运行过程中也可以通过命令动态设置淘汰策略,并通过 INFO 命令监控缓存的 miss 和 hit,来进行调优。

淘汰策略的内部实现

  • 客户端执行一个命令,导致 Redis 中的数据增加,占用更多内存
  • Redis 检查内存使用量,如果超出 maxmemory 限制,根据策略清除部分 key
  • 继续执行下一条命令,以此类推

在这个过程中,内存使用量会不断地达到 limit 值,然后超过,然后删除部分 key,使用量又下降到 limit 值之下。

如果某个命令导致大量内存占用(比如通过新key保存一个很大的set),在一段时间内,可能内存的使用量会明显超过 maxmemory 限制。

Redis与Memcached的区别

两者都是非关系型内存键值数据库,现在公司一般都是用 Redis 来实现缓存,而且 Redis 自身也越来越强大了!Redis 与 Memcached 的区别请参考:Redis与Memcached的区别

事务

Redis 通过 MULTI、EXEC、WATCH 等命令来实现事务(transaction)功能。事务提供了一种将多个命令请求打包,然后一次性、按顺序地执行多个命令的机制,并且在事务执行期间,服务器不会中断事务而改去执行其他客户端的命令请求,它会将事务中的所有命令都执行完毕,然后才去处理其他客户端的命令请求。

事务中的多个命令被一次性发送给服务器,而不是一条一条发送,这种方式被称为流水线,可以减少客户端与服务器之间的网络通信次数从而提升性能。

在传统的关系式数据库中,常用 ACID 性质来检验事务功能的可靠性和安全性。在 Redis 中,事务总是具有原子性(Atomicity)、一致性(Consistency)和隔离性(Isolation),并且当 Redis 运行在某种特定的持久化模式下时,事务也具有持久性(Durability)。

  • 事件

Redis 服务器是一个事件驱动程序。

  • 文件事件

服务器通过套接字与客户端或者其它服务器进行通信,文件事件就是对套接字操作的抽象。

Redis 基于 Reactor 模式开发了自己的网络事件处理器,使用 I/O 多路复用程序来同时监听多个套接字,并将到达的事件传送给文件事件分派器,分派器会根据套接字产生的事件类型调用相应的事件处理器。

  • 时间事件

服务器有一些操作需要在给定的时间点执行,时间事件是对这类定时操作的抽象。

时间事件又分为:

  • 定时事件:是让一段程序在指定的时间之内执行一次
  • 周期性事件:是让一段程序每隔指定时间就执行一次

目前Redis只使用周期性事件,而没有使用定时事件。 一个事件时间主要由三个属性组成:

  • id:服务器为时间事件创建的全局唯一ID
  • when:毫秒精度的UNIX时间戳,记录了时间事件的到达时间
  • timeProc:时间事件处理器,一个函数

实现服务器将所有时间事件都放在一个无序链表中,每当时间事件执行器运行时,遍历整个链表,查找所有已到达的时间事件,并调用相应的事件处理器。(该链表为无序链表,不按when属性的大小排序)

  • 事件的调度与执行

服务器需要不断监听文件事件的套接字才能得到待处理的文件事件,但是不能一直监听,否则时间事件无法在规定的时间内执行,因此监听时间应该根据距离现在最近的时间事件来决定。

Sentinel

Sentinel(哨兵)可以监听集群中的服务器,并在主服务器进入下线状态时,自动从从服务器中选举出新的主服务器。

Redis集群生产环境高可用方案实战过程

分片

分片是将数据划分为多个部分的方法,可以将数据存储到多台机器里面,这种方法在解决某些问题时可以获得线性级别的性能提升。

假设有 4 个 Redis 实例 R0,R1,R2,R3,还有很多表示用户的键 user:1,user:2,… ,有不同的方式来选择一个指定的键存储在哪个实例中。

最简单的方式是范围分片,例如用户 id 从 0~1000 的存储到实例 R0 中,用户 id 从 1001~2000 的存储到实例 R1 中,等等。但是这样需要维护一张映射范围表,维护操作代价很高。

还有一种方式是哈希分片,使用 CRC32 哈希函数将键转换为一个数字,再对实例数量求模就能知道应该存储的实例。

根据执行分片的位置,可以分为三种分片方式:

  • 客户端分片:客户端使用一致性哈希等算法决定键应当分布到哪个节点。
  • 代理分片:将客户端请求发送到代理上,由代理转发请求到正确的节点上。
  • 服务器分片:Redis Cluster。

复制

通过使用 slaveof host port 命令来让一个服务器成为另一个服务器的从服务器。

一个从服务器只能有一个主服务器,并且不支持主主复制。

  • 连接过程

    • 主服务器创建快照文件,发送给从服务器,并在发送期间使用缓冲区记录执行的写命令。快照文件发送完毕之后,开始向从服务器发送存储在缓冲区中的写命令
    • 从服务器丢弃所有旧数据,载入主服务器发来的快照文件,之后从服务器开始接受主服务器发来的写命令
    • 主服务器每执行一次写命令,就向从服务器发送相同的写命令
  • 主从链

随着负载不断上升,主服务器可能无法很快地更新所有从服务器,或者重新连接和重新同步从服务器将导致系统超载。为了解决这个问题,可以创建一个中间层来分担主服务器的复制工作。中间层的服务器是最上层服务器的从服务器,又是最下层服务器的主服务器。

Redis中缓存雪崩、缓存穿透等问题的解决方案

缓存雪崩

缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。

解决方案
  • 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
  • 一般并发量不是特别多的时候,使用最多的解决方案是加锁排队。
  • 给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存。
缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。

解决方案
  • 接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截;
  • 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击
  • 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力

附加

  • 对于空间的利用到达了一种极致,那就是Bitmap和布隆过滤器(Bloom Filter)。
  • Bitmap: 典型的就是哈希表
  • 缺点是,Bitmap对于每个元素只能记录1bit信息,如果还想完成额外的功能,恐怕只能靠牺牲更多的空间、时间来完成了。

布隆过滤器(推荐)

  • 就是引入了k(k>1)k(k>1)个相互独立的哈希函数,保证在给定的空间、误判率下,完成元素判重的过程。
  • 它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
  • Bloom-Filter算法的核心思想就是利用多个不同的Hash函数来解决“冲突”。
  • Hash存在一个冲突(碰撞)的问题,用同一个Hash得到的两个URL的值有可能相同。为了减少冲突,我们可以多引入几个Hash,如果通过其中的一个Hash值我们得出某元素不在集合中,那么该元素肯定不在集合中。只有在所有的Hash函数告诉我们该元素在集合中时,才能确定该元素存在于集合中。这便是Bloom-Filter的基本思想。
  • Bloom-Filter一般用于在大数据量的集合中判定某元素是否存在。
缓存击穿

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。和缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。

解决方案
  • 设置热点数据永远不过期。
  • 加互斥锁,互斥锁
缓存预热

缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!

解决方案
  • 直接写个缓存刷新页面,上线时手工操作一下;
  • 数据量不大,可以在项目启动的时候自动进行加载;
  • 定时刷新缓存;
缓存降级

当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。

缓存降级的最终目的是保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入购物车、结算)。

在进行降级之前要对系统进行梳理,看看系统是不是可以丢卒保帅;从而梳理出哪些必须誓死保护,哪些可降级;比如可以参考日志级别设置预案:

一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级;

警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送告警;

错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级;

严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级。

服务降级的目的,是为了防止Redis服务故障,导致数据库跟着一起发生雪崩问题。因此,对于不重要的缓存数据,可以采取服务降级策略,例如一个比较常见的做法就是,Redis出现问题,不去数据库查询,而是直接返回默认值给用户。

热点数据和冷数据

热点数据,缓存才有价值

对于冷数据而言,大部分数据可能还没有再次访问到就已经被挤出内存,不仅占用内存,而且价值不大。频繁修改的数据,看情况考虑使用缓存

对于热点数据,比如我们的某IM产品,生日祝福模块,当天的寿星列表,缓存以后可能读取数十万次。再举个例子,某导航产品,我们将导航信息,缓存以后可能读取数百万次。

数据更新前至少读取两次,缓存才有意义。这个是最基本的策略,如果缓存还没有起作用就失效了,那就没有太大价值了。

那存不存在,修改频率很高,但是又不得不考虑缓存的场景呢?有!比如,这个读取接口对数据库的压力很大,但是又是热点数据,这个时候就需要考虑通过缓存手段,减少数据库的压力,比如我们的某助手产品的,点赞数,收藏数,分享数等是非常典型的热点数据,但是又不断变化,此时就需要将数据同步保存到Redis缓存,减少数据库压力。

缓存热点key

缓存中的一个Key(比如一个促销商品),在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

解决方案

对缓存查询加锁,如果KEY不存在,就加锁,然后查DB入缓存,然后解锁;其他进程如果发现有锁就等待,然后等解锁后返回数据或者进入DB查询

以上内容参考链接:https://blog.csdn.net/ThinkWo...

Redis 优化最佳实践

我们就来总结一下,在使用Redis时的最佳实践方式,主要包含两个层面:业务层面、运维层面。

由于我之前写过很多UGC后端服务,在大量场景下用到了Redis,这个过程中也踩过很多坑,所以在使用过程中也总结了一套合理的使用方法。

后来做基础架构,开发Codis、Redis相关的中间件,在这个阶段关注领域从使用层面下沉到Redis的开发和运维,更多聚焦在Redis的内部实现和运维过程中产生的各种问题,在这块也积累了一些经验。

下面就针对这两块,分享一下我认为比较合理的Redis使用和运维方法,不一定最全面,也可能与你使用Redis的方法不同,但以下这些方法都是我在踩坑之后总结的实际经验,供你参考。关注公众号Java技术栈回复redis获取系列Redis教程。

业务层面主要是开发人员需要关注,也就是开发人员在写业务代码时,如何合理地使用Redis。开发人员需要对Redis有基本的了解,才能在合适的业务场景使用Redis,从而避免业务层面导致的延迟问题。

在开发过程中,业务层面的优化建议如下:

  • key的长度尽量要短,在数据量非常大时,过长的key名会占用更多的内存
  • 一定避免存储过大的数据(大value),过大的数据在分配内存和释放内存时耗时严重,会阻塞主线程
  • Redis 4.0以上建议开启lazy-free机制,释放大value时异步操作,不阻塞主线程
  • 建议设置过期时间,把Redis当做缓存使用,尤其在数量很大的时,不设置过期时间会导致内存的无限增长
  • 不使用复杂度过高的命令,例如SORT、SINTER、SINTERSTORE、ZUNIONSTORE、ZINTERSTORE,使用这些命令耗时较久,会阻塞主线程
  • 查询数据时,一次尽量获取较少的数据,在不确定容器元素个数的情况下,避免使用LRANGE key 0 -1,ZRANGE key 0 -1这类操作,应该设置具体查询的元素个数,推荐一次查询100个以下元素
  • 写入数据时,一次尽量写入较少的数据,例如HSET key value1 value2 value3...,-控制一次写入元素的数量,推荐在100以下,大数据量分多个批次写入
  • 批量操作数据时,用MGET/MSET替换GET/SET、HMGET/MHSET替换HGET/HSET,减少请求来回的网络IO次数,降低延迟,对于没有批量操作的命令,推荐使用pipeline,一次性发送多个命令到服务端
  • 禁止使用KEYS命令,需要扫描实例时,建议使用SCAN,线上操作一定要控制扫描的频率,避免对Redis产生性能抖动
  • 避免某个时间点集中过期大量的key,集中过期时推荐增加一个随机时间,把过期时间打散,降低集中过期key时Redis的压力,避免阻塞主线程
  • 根据业务场景,选择合适的淘汰策略,通常随机过期要比LRU过期淘汰数据更快
  • 使用连接池访问Redis,并配置合理的连接池参数,避免短连接,TCP三次握手和四次挥手的耗时也很高
  • 只使用db0,不推荐使用多个db,使用多个db会增加Redis的负担,每次访问不同的db都需要执行SELECT命令,如果业务线不同,建议拆分多个实例,还能提高单个实例的性能
  • 读的请求量很大时,推荐使用读写分离,前提是可以容忍从节数据更新不及时的问题
  • 写请求量很大时,推荐使用集群,部署多个实例分摊写压力

运维层面

目的是合理规划Redis的部署和保障Redis的稳定运行,主要优化如下:

  • 不同业务线部署不同的实例,各自独立,避免混用,推荐不同业务线使用不同的机器,根据业务重要程度划分不同的分组来部署,避免某一个业务线出现问题影响其他业务线
  • 保证机器有足够的CPU、内存、带宽、磁盘资源,防止负载过高影响Redis性能
  • 以master-slave集群方式部署实例,并分布在不同机器上,避免单点,slave必须设置为readonly
  • master和slave节点所在机器,各自独立,不要交叉部署实例,通常备份工作会在slave上做,做备份时会消耗机器资源,交叉部署会影响到master的性能
  • 推荐部署哨兵节点增加可用性,节点数量至少3个,并分布在不同机器上,实现故障自动故障转移
  • 提前做好容量规划,一台机器部署实例的内存上限,最好是机器内存的一半,主从全量同步时会占用最多额外一倍的内存空间,防止网络大面积故障引发所有master-slave的全量同步导致机器内存被吃光
  • 做好机器的CPU、内存、带宽、磁盘监控,在资源不足时及时报警处理,Redis使用Swap后性能急剧下降,网络带宽负载过高访问延迟明显增大,磁盘IO过高时开启AOF会拖慢Redis的性能
  • 设置最大连接数上限,防止过多的客户端连接导致服务负载过高
  • 单个实例的使用内存建议控制在20G以下,过大的实例会导致备份时间久、资源消耗多,主从全量同步数据时间阻塞时间更长
  • 设置合理的slowlog阈值,推荐10毫秒,并对其进行监控,产生过多的慢日志需要及时报警 设置合理的复制缓冲区repl-backlog大小,适当调大repl-backlog可以降低主从全量复制的概率
  • 设置合理的slave节点client-output-buffer-limit大小,对于写入量很大的实例,适当调大可以避免主从复制中断问题
  • 备份时推荐在slave节点上做,不影响master性能
  • 不开启AOF或开启AOF配置为每秒刷盘,避免磁盘IO消耗降低Redis性能
  • 当实例设置了内存上限,需要调大内存上限时,先调整slave再调整master,否则会导致主从节点数据不一致
  • 对Redis增加监控,监控采集info信息时,使用长连接,频繁的短连接也会影响Redis性能,redis性能监控指标,参考这个文章
  • 线上扫描整个实例数时,记得设置休眠时间,避免扫描时QPS突增对Redis产生性能抖
  • 做好Redis的运行时监控,尤其是expired\_keys、evicted\_keys、latest\_fork\_usec指标,短时间内这些指标值突增可能会阻塞整个实例,引发性能问题

以上就是我在使用Redis和开发Redis相关中间件时,总结出来Redis推荐的实践方法,以上提出的这些方面,都或多或少在实际使用中遇到过。

可见,要想稳定发挥Redis的高性能,需要在各个方面做好工作,但凡某一个方面出现问题,必然会影响到Redis的性能,这对我们使用和运维提出了更高的要求。

如果你在使用Redis过程中,遇到更多的问题或者有更好的使用经验,可以留言一起探讨!

出处:kaito-kidd.com/2020/07/04/redis-best-practices/

Redis其它总结

阿里云Redis开发规范学习总结

目前 Redis 可视化工具最全的横向评测

Redis 性能测试工具介绍

Redis 可视化管理工具

Redis 越来越慢?常见延迟问题定位与分析

Redis 分布式集群部署

原理:

  • Redis集群采用一致性哈希槽的方式将集群中每个主节点都分配一定的哈希槽,对写入的数据进行哈希后分配到某个主节点进行存储。
  • 集群使用公式(CRC16 key)& 16384计算键key数据那个槽。
  • 16384个slot均匀分布在各个节点上。
  • 集群中每个主节点将承担一部分槽点的维护,而槽点中存储着数据,每个主节点都有至少一个从节点用于高可用。

节点通信方式:
  • 开启一个端口 设置的端口号+10000,用于集群之间节点通信交换信息。
  • 每个节点默认每秒10次选择随机5个节点发送ping消息,将自身信息和知道的集群信息传递,收到ping消息后返回pong消息做回复,最后通过这种随机的消息交换,最终每个节点将获得所有信息。
  • 当某个主节点挂掉,所有节点将会发现主节点挂掉了,作为主节点的从节点,就会接替主节点的工作,然后告诉所有其它节点,他成为了主。这样其它存活节点,就将它们维护的信息表更新从节点将接任做主,如果都挂掉集群将报错。当从一个节点操作,根据一致性哈希计算后将存储在其中一个主节点中,从节点将同步主的数据。

  • redis cluster是去中心化的,集群中的每个节点都是平等的关系,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃。

  • 搭建集群时,会为每一个分片的主节点,对应一个从节点。实现slaveof功能,同时当主节点down,实现sentinel哨兵的自动failover切换功能

Redis分布式集群(部署):

端口号:7000-7005

本次分布式分片集群在一台LInux系统即可,只需要安装多个实例作为集群配置。

安装ruby环境支持:
yum -y install ruby rubygems

yum安装2.0.0版本,但是gem需要2.2.2版本以上,所以选择编译

下载并安装ruby环境:
wget https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.1.tar.gz
tar xf ruby-2.6.1.tar.gz && cd ruby-2.6.1/
./configure --prefix=/usr/local/ruby
make && make install && echo $?
echo 'export PATH=$PATH:/usr/local/ruby/bin' >> /etc/profile
source /etc/profile
修改gem工具国内源:
# 查看gem工具源地址
gem sources -l
# 添加一个阿里云的gem工具源
gem sources -a http://mirrors.aliyun.com/rubygems/
# 删除gem工具默认国外源
gem sources --remove https://rubygems.org/
# 下载当前最新版本集群插件
gem install redis -v 4.1.0
集群节点准备:
mkdir /data/700{0..5}
配置7000端口实例:
vim /data/7000/redis.conf
port 7000
daemonize yes
pidfile /data/7000/redis.pid
loglevel notice
logfile "/data/7000/redis.log"
dbfilename dump.rdb
dir /data/7000
protected-mode no
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes
拷贝其他端口实例:
# 拷贝配置文件
cp /data/7000/redis.conf /data/7001/
cp /data/7000/redis.conf /data/7002/
cp /data/7000/redis.conf /data/7003/
cp /data/7000/redis.conf /data/7004/
cp /data/7000/redis.conf /data/7005/

# 修改配置文件内容
sed -i 's#7000#7001#g' /data/7001/redis.conf
sed -i 's#7000#7002#g' /data/7002/redis.conf
sed -i 's#7000#7003#g' /data/7003/redis.conf
sed -i 's#7000#7004#g' /data/7004/redis.conf
sed -i 's#7000#7005#g' /data/7005/redis.conf
启动所有实例:
redis-server /data/7000/redis.conf
redis-server /data/7001/redis.conf
redis-server /data/7002/redis.conf
redis-server /data/7003/redis.conf
redis-server /data/7004/redis.conf
redis-server /data/7005/redis.conf
创建命令软链接:
(这个命令过期了,现在使用redis-cli命令)(可选执行命令)
ln -s /usr/local/redis-5.0.2/src/redis-trib.rb /usr/sbin/
查看进程:
ps -ef |grep redis-server

加入所有实例节点到集群管理:
# --replicas 1",1是代表每一个主有一个从,后面的是所有节点的地址与端口信息
redis-cli --cluster create --cluster-replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

分布式主从规则为,前三个实例节点是主,对应的后面三个实例节点为从节点,如果replicas 2,那就多加3个实例节点

查看主节点状态:
redis-cli -p 7000 cluster nodes|grep master

查看从节点状态:
redis-cli -p 7000 cluster nodes|grep slave

Redis-分布式集群(管理)

集群节点增加准备:

mkdir /data/700{6..7}

拷贝其他端口实例:

# 拷贝配置文件
cp /data/7000/redis.conf /data/7006/
cp /data/7000/redis.conf /data/7007/

# 修改配置文件内容
sed -i 's#7000#7006#g' /data/7006/redis.conf
sed -i 's#7000#7007#g' /data/7007/redis.conf

启动新节点实例:

redis-server /data/7006/redis.conf
redis-server /data/7007/redis.conf
查看进程:
ps -ef |grep redis-server

添加主节点:(7000实例是管理节点)
#'把7006实例添加到7000实例这个主节点所在集群内(此时已经有了4个主节点)
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000
查看主节点状态:
redis-cli -p 7000 cluster nodes|grep master

转移slot(重新分片):
#'操作集群管理节点从新分配,并在交互界面指定分片大小、选择接收分片的节点ID
redis-cli --cluster reshard 127.0.0.1:7000

How many slots do you want to move (from 1 to 16384)? 4096
#通过人工手动计算数据分片总大小除以主节点后的数字

What is the receiving node ID? 2129d28f0a86fc89571e49a59a0739812cff7953
#选择接收数据分片的节点ID,(这是新增节点7006实例的ID号)

Source node #1: all
#选择从哪些源主节点重新分片给新主节点)(all是所有节点)

Do you want to proceed with the proposed reshard plan (yes/no)? yes           
#确认修改以上的操作
重新查看主节点状态:(可以看到集群数据的重新分片)
redis-cli -p 7000 cluster nodes|grep master

添加从节点:
#'把7007实例节点添加到7006实例主节点内,并指定对应7006实例主节点坐在集群的管理节点
redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7000 --cluster-slave --cluster-master-id 2129d28f0a86fc89571e49a59a0739812cff7953
查看从节点状态:
redis-cli -p 7000 cluster nodes|grep slave

集群节点删除准备:

移动要删除节点的数据分片:
#'操作集群管理节点从新分配,并在交互界面指定分片大小、选择接收分片的节点ID
redis-cli --cluster reshard 127.0.0.1:7000

#方法是根据要删除master节点的分片位置,然后一个组分一个节点 , 也可以直接移动所有数据片到一个节点

How many slots do you want to move (from 1 to 16384)? 1365                    
#通过人工手动查看数据分片总大小

What is the receiving node ID? e64f9074a3733fff7baa9a4848190e56831d5447
#选择接收数据分片的节点ID,(这是新增节点7006实例的ID号)

Source node #1: 2129d28f0a86fc89571e49a59a0739812cff7953
#选择从哪些源主节点重新分片给新主节点(这是要删除的主节点的ID号)

Source node #2: done
#这是结束命令

Do you want to proceed with the proposed reshard plan (yes/no)? yes           
#确认修改以上的操作
重新查看主节点状态:(可以看到集群数据的重新分片)
redis-cli -p 7000 cluster nodes|grep master

继续移动数据片:
#'操作集群管理节点从新分配,并在交互界面指定分片大小、选择接收分片的节点ID
redis-cli --cluster reshard 127.0.0.1:7000

# 方法是根据要删除master节点的分片位置,然后一个组分一个节点 , 也可以直接移动所有数据片到一个节点

How many slots do you want to move (from 1 to 16384)? 1366                    #通过人工手动查看数据分片总大小

What is the receiving node ID? f6c1aaea3a8c56e0c7dee8ad7ae17e26dd04244c
#选择接收数据分片的节点ID,(这是新增节点7006实例的ID号)

Source node #1: 2129d28f0a86fc89571e49a59a0739812cff7953
#选择从哪些源主节点重新分片给新主节点(这是要删除的主节点的ID号)

Source node #2: done
#这是结束命令

Do you want to proceed with the proposed reshard plan (yes/no)? yes           
#确认修改以上的操作
重新查看主节点状态:(可以看到集群数据的重新分片)
redis-cli -p 7000 cluster nodes|grep master

最后一次移动数据片:
#'操作集群管理节点从新分配,并在交互界面指定分片大小、选择接收分片的节点ID
redis-cli --cluster reshard 127.0.0.1:7000

#方法是根据要删除master节点的分片位置,然后一个组分一个节点 , 也可以直接移动所有数据片到一个节点

How many slots do you want to move (from 1 to 16384)? 1365                    
#通过人工手动查看数据分片总大小

What is the receiving node ID? 5a0df4ea0af5f35c1248e45e88d44c3f2e10169f
Source node #1: 2129d28f0a86fc89571e49a59a0739812cff7953
Source node #2: done                
重新查看主节点状态:(可以看到集群数据的重新分片)
redis-cli -p 7000 cluster nodes|grep master

删除清空数据片的主节点:
#'删除已经清空数据的7006实例
redis-cli --cluster del-node 127.0.0.1:7006 2129d28f0a86fc89571e49a59a0739812cff7953

#删除没有主库的7007实例
redis-cli --cluster del-node 127.0.0.1:7007 821bcf78c5e4c0b08aa7a5d514214b657ebec4ab

其他配置管理:

#内存信息查看
redis-cli -p 6382 -a redhat info memory

#设置最大只能使用100MB的内存
redis-cli -p 6382 -a redhat config set maxmemory 102400000

史上最全、最新的Redis面试题(最新版)

查看原文

赞 17 收藏 15 评论 0

民工哥 发布了文章 · 4月15日

火了!这款免费、开源的终端资源监控器是真的牛逼...

对于系统运维、维护或开发人员来说,能很好、清楚的了解系统各方面资源的使用情况,这也是一个IT人员必备的技能之一。

对于Linux系统来说,我们在日常可以借助一些系统自带的命令工具,如:top、htop、iotopiostatifstatvmstat等等,有时候我也可以借助一些第三方的工具:「 系统之眼!Linux系统性能监控工具Glances 」来查看系统资源的利用情况。

有一个好用的工具也是提高我们工作效率的一种手段。今天,民工哥就给大家介绍一款好用的、并且在 UI 设计上十分美观的终端资源监视器 ——Bpytop,Bpytop 是 bashtop 的 python 版本。

图片

功能特点介绍

  • 易于使用,带有受游戏启发的菜单系统。

  • 完全支持鼠标,所有带有突出显示键的按钮都可单击,并且鼠标滚动可在进程列表和菜单框中使用。

  • 快速,反应灵敏的UI,带有UP,DOWN键可进行过程选择。

  • 用于显示所选进程的详细统计信息的功能。

  • 具有过滤过程的能力,可以输入多个过滤器。

  • 在排序选项之间轻松切换。

  • 将SIGTERM,SIGKILL,SIGINT发送到选定的进程。

  • 用于更改所有配置文件选项的UI菜单。

  • 网络使用情况的自动缩放图。

  • 如果有新版本可用,则在菜单中显示消息

  • 显示磁盘的当前读写速度

所需环境及安装

1、安装环境

  • Python3(v3.7或更高版本)

  • psutil模块(v5.7.0或更高版本)

[root@centos7 ~]# /usr/bin/python3 -m pip install psutilWARNING: Running pip install with root privileges is generally not a good idea. Try `__main__.py install --user` instead.Collecting psutil  Using cached https://files.pythonhosted.org/packages/e1/b0/7276de53321c12981717490516b7e612364f2cb372ee8901bd4a66a000d7/psutil-5.8.0.tar.gzInstalling collected packages: psutil  Running setup.py install for psutil ... doneSuccessfully installed psutil-5.8.0

如果在安装上面的模块出现如下提示

 psutil/_psutil_common.c:9:20: fatal error: Python.h: No such file or directory     #include <Python.h>                        ^    compilation terminated.    error: command 'gcc' failed with exit status 1        ----------------------------------------Command "/usr/bin/python3 -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-5ffj6s3k/psutil/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-qbw2w01r-record/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-build-5ffj6s3k/psutil/

解决方法如下

[root@centos7 ~]# yum install python-devel python3-devel -y

2、安装bpytop

从 Github 克隆整个仓库

[root@centos7 ~]# git clone https://github.com/aristocratos/bpytop.gitCloning into 'bpytop'...remote: Enumerating objects: 191, done.remote: Counting objects: 100% (191/191), done.remote: Compressing objects: 100% (105/105), done.remote: Total 1348 (delta 119), reused 157 (delta 86), pack-reused 1157Receiving objects: 100% (1348/1348), 1002.09 KiB | 349.00 KiB/s, done.Resolving deltas: 100% (852/852), done.

编译安装

[root@centos7 ~]# cd bpytop/[root@centos7 bpytop]# make install

命令行选项

usage: bpytop.py [-h] [-b BOXES] [-lc] [-v] [--debug]optional arguments:  -h, --help            show this help message and exit  -b BOXES, --boxes BOXES  which boxes to show at start, example: -b "cpu mem net proc"  -lc, --low-color      disable truecolor, converts 24-bit colors to 256-color  -v, --version         show version info and exit  --debug               start with loglevel set to DEBUG overriding value set in config

界面与使用

主界面

图片

图片

图片

按ESC 选择HELP

图片

快捷键介绍
o               #进入选项页面
m               #切换mini模式和一般模式
h               #查看帮助文档    
q , ctrl+c      #退出程序
ESC , shift+m   #进入主菜单
+ / -           #快速修改页面刷新时间间隔
n               #切换网卡
f               #过滤进程名称
e               #进程树状展示            

图片

迷你界面

图片

树状显示

图片

参考资料:https://github.com/aristocrat... 项目介绍
查看原文

赞 1 收藏 1 评论 0

民工哥 发布了文章 · 4月15日

Kubernetes 之 kubectl 使用指南

kubectl 是 Kubernetes 自带的客户端,可以用它来直接操作 Kubernetes 集群。

日常在使用 Kubernetes 的过程中,kubectl 工具可能是最常用的工具了,所以当我们花费大量的时间去研究和学习 Kuernetes 的时候,那么我们就非常有必要去了解下如何高效的使用它了。

从用户角度来说,kubectl 就是控制 Kubernetes 的驾驶舱,它允许你执行所有可能的 Kubernetes 操作;从技术角度来看,kubectl 就是 Kubernetes API 的一个客户端而已。

Kubernetes API 是一个 HTTP REST API 服务,该 API 服务才是 Kubernetes 的真正用到的用户接口,所以 Kubernetes 通过该 API 进行实际的控制。这也就意味着每个 Kubernetes 的操作都会通过 API 端点暴露出去,当然也就可以通过对这些 API 端口进行 HTTP 请求来执行相应的操作。所以,kubectl 最主要的工作就是执行 Kubernetes API 的 HTTP 请求。

工具使用参数

get       #显示一个或多个资源
describe  #显示资源详情
create    #从文件或标准输入创建资源
update   #从文件或标准输入更新资源
delete   #通过文件名、标准输入、资源名或者 label 删除资源
log       #输出 pod 中一个容器的日志
rolling-update  #对指定的 RC 执行滚动升级
exec  #在容器内部执行命令
port-forward #将本地端口转发到 Pod
proxy   #为 Kubernetes API server 启动代理服务器
run     #在集群中使用指定镜像启动容器
expose   #将 SVC 或 pod 暴露为新的 kubernetes service
label     #更新资源的 label
config   #修改 kubernetes 配置文件
cluster-info #显示集群信息
api-versions #以”组/版本”的格式输出服务端支持的 API 版本
version       #输出服务端和客户端的版本信息
help         #显示各个命令的帮助信息
ingress-nginx  #管理 ingress 服务的插件(官方安装和使用方式)

使用相关配置

# Kubectl自动补全
$ source <(kubectl completion zsh)
$ source <(kubectl completion bash)

# 显示合并后的 kubeconfig 配置
$ kubectl config view

# 获取pod和svc的文档
$ kubectl explain pods,svc

创建资源对象

分步骤创建

# yaml
kubectl create -f xxx-rc.yaml
kubectl create -f xxx-service.yaml

# json
kubectl create -f ./pod.json
cat pod.json | kubectl create -f -

# yaml2json
kubectl create -f docker-registry.yaml --edit -o json

一次性创建

kubectl create -f xxx-service.yaml -f xxx-rc.yaml

根据目录下所有的 yaml 文件定义内容进行创建

kubectl create -f <目录>

使用 url 来创建资源

kubectl create -f https://git.io/vPieo

查看资源对象

查看所有 Node 或 Namespace 对象

kubectl get nodes
kubectl get namespace

查看所有 Pod 对象

# 查看子命令帮助信息
kubectl get --help

# 列出默认namespace中的所有pod
kubectl get pods

# 列出指定namespace中的所有pod
kubectl get pods --namespace=test

# 列出所有namespace中的所有pod
kubectl get pods --all-namespaces

# 列出所有pod并显示详细信息
kubectl get pods -o wide
kubectl get replicationcontroller web
kubectl get -k dir/
kubectl get -f pod.yaml -o json
kubectl get rc/web service/frontend pods/web-pod-13je7
kubectl get pods/app-prod-78998bf7c6-ttp9g --namespace=test -o wide
kubectl get -o template pod/web-pod-13je7 --template={{.status.phase}}

# 列出该namespace中的所有pod包括未初始化的
kubectl get pods,rc,services --include-uninitialized

查看所有 RC 对象

kubectl get rc

查看所有 Deployment 对象

# 查看全部deployment
kubectl get deployment

# 列出指定deployment
kubectl get deployment my-app

查看所有 Service 对象

kubectl get svc
kubectl get service

查看不同 Namespace 下的 Pod 对象

kubectl get pods -n default
kubectl get pods --all-namespace

查看资源描述

显示 Pod 详细信息

kubectl describe pods/nginx
kubectl describe pods my-pod
kubectl describe -f pod.json

查看 Node 详细信息

kubectl describe nodes c1

查看 RC 关联的 Pod 信息

kubectl describe pods <rc-name>

更新修补资源

滚动更新

# 滚动更新 pod frontend-v1
kubectl rolling-update frontend-v1 -f frontend-v2.json

# 更新资源名称并更新镜像
kubectl rolling-update frontend-v1 frontend-v2 --image=image:v2

# 更新 frontend pod 中的镜像
kubectl rolling-update frontend --image=image:v2

# 退出已存在的进行中的滚动更新
kubectl rolling-update frontend-v1 frontend-v2 --rollback

# 强制替换; 删除后重新创建资源; 服务会中断
kubectl replace --force -f ./pod.json

# 添加标签
kubectl label pods my-pod new-label=awesome

# 添加注解
kubectl annotate pods my-pod icon-url=http://goo.gl/XXBTWq

修补资源

# 部分更新节点
kubectl patch node k8s-node-1 -p '{"spec":{"unschedulable":true}}'

# 更新容器镜像;spec.containers[*].name 是必须的,因为这是合并的关键字
kubectl patch pod valid-pod -p \
    '{"spec":{"containers":[{"name":"kubernetes-serve-hostname","image":"new image"}]}}'
Scale 资源
# Scale a replicaset named 'foo' to 3
kubectl scale --replicas=3 rs/foo

# Scale a resource specified in "foo.yaml" to 3
kubectl scale --replicas=3 -f foo.yaml

# If the deployment named mysql's current size is 2, scale mysql to 3
kubectl scale --current-replicas=2 --replicas=3 deployment/mysql

# Scale multiple replication controllers
kubectl scale --replicas=5 rc/foo rc/bar rc/baz

删除资源对象

基于 xxx.yaml 文件删除 Pod 对象

# yaml文件名字按照你创建时的文件一致
kubectl delete -f xxx.yaml

删除包括某个 label 的 pod 对象

kubectl delete pods -l name=<label-name>

删除包括某个 label 的 service 对象

kubectl delete services -l name=<label-name>

删除包括某个 label 的 pod 和 service 对象

kubectl delete pods,services -l name=<label-name>

删除所有 pod/services 对象

kubectl delete pods --all
kubectl delete service --all
kubectl delete deployment --all

编辑资源文件

在编辑器中编辑任何 API 资源

# 编辑名为docker-registry的service
kubectl edit svc/docker-registry

直接执行命令

在寄主机上,不进入容器直接执行命令

执行 pod 的 date 命令,默认使用 pod 的第一个容器执行

kubectl exec mypod -- date
kubectl exec mypod --namespace=test -- date

指定 pod 中某个容器执行 date 命令

kubectl exec mypod -c ruby-container -- date

进入某个容器

kubectl exec mypod -c ruby-container -it -- bash

查看容器日志

直接查看日志

# 不实时刷新
kubectl logs mypod
kubectl logs mypod --namespace=test

查看日志实时刷新

kubectl logs -f mypod -c ruby-container

常用命令总结

!image.png

image.png

image.png

作者: Escape 链接: https//www.escapelife.site/posts/2b31e1a2.html

查看原文

赞 1 收藏 1 评论 0

民工哥 发布了文章 · 4月15日

每天学一个 Linux 命令(115):accton

命令简介

accton 命令是 Linux 系统进程管理命令之一,它的作用是打开进程统计,如果命令后面不带任何参数,就是关闭进程统计。

默认系统是没有安装此命令的,需要用户在使用前自行安装,命令如下。

#CentOS
[root@centos7 ~]# acct
-bash: acct: command not found
[root@centos7 ~]# yum install psacct -y 
#Debian && Ubuntu
apt-get install acct
#Fedora
dnf install psacct

安装完成之后,默认情况下,psacct 服务是关闭状态,在 RHEL/CentOS/Fedora 待系统下,需要用户手动去开启该服务。

[root@centos7 ~]# systemctl status psacct.service
● psacct.service - Kernel process accounting
   Loaded: loaded (/usr/lib/systemd/system/psacct.service; disabled; vendor preset: disabled)
   Active: inactive (dead)
[root@centos7 ~]# systemctl start psacct.service
[root@centos7 ~]# systemctl status psacct.service
● psacct.service - Kernel process accounting
   Loaded: loaded (/usr/lib/systemd/system/psacct.service; disabled; vendor preset: disabled)
   Active: active (exited) since Mon 2021-03-29 08:00:51 EDT; 2s ago
  Process: 25987 ExecStart=/usr/sbin/accton /var/account/pacct (code=exited, status=0/SUCCESS)
  Process: 25985 ExecStartPre=/usr/libexec/psacct/accton-create (code=exited, status=0/SUCCESS)
 Main PID: 25987 (code=exited, status=0/SUCCESS)

语法格式

accton [OPTION] on|off|ACCOUNTING_FILE

选项说明

-p filename    #指定密码文件filename
--version  #显示ac版本并退出
--help     #打印命令概要

准确的说 acct 是一个工具包,里面包含有针对用户连接时间、进程执行情况等进行统计的工具。它可以记录用户登录信息。用户所执行的程序,程序执行情况信息等。acct 包含以下工具包命令:

ac   #显示登录账号的简要信息
accton    #打开或关闭进程记录功能
last      #显示曾经登录过的用户
lastcomm  #显示已执行过的命令
sa        #进程用户记录信息的摘要
dump-utmp   #输出utmp文件内容
dump-acct   #输出acct或pacct文件内容

accton 命令参数

on               Activate process accounting and use default file
off              Deactivate process accounting
ACCOUNTING_FILE  Activate (if not active) and save information in
this file
 
The system's default process accounting file is '/var/account/pacct'.
 
Report bugs to <bug-acct@gnu.org>

相关的详细信息可查看帮助文件

应用举例

#显示用户连接时间的统计信息
[root@centos7 ~]# ac
 total      173.79

#输出每天的总登录时间(小时)
[root@centos7 ~]# ac -d
Aug 20 total       13.60
Aug 30 total        3.19
Dec 24 total        0.28
Jan  2 total       21.99
Jan 15 total        1.22
Jan 16 total       23.75
Jan 17 total       31.34
Mar 10 total        7.38
Mar 21 total        2.84
Mar 23 total        0.04
Mar 24 total       24.62
Mar 27 total        0.66
Mar 28 total       22.98
Today total       19.90

#显示每个用户的总登录时间(小时)
[root@centos7 ~]# ac -p
 root                               173.79
 total      173.79

显示指定用户的每天登录时长(小时)

[root@centos7 ~]# ac -d mingongge
[root@centos7 ~]# ac -d root
Aug 20 total       13.60
Aug 30 total        3.19
Dec 24 total        0.28
Jan  2 total       21.99
Jan 15 total        1.22
Jan 16 total       23.75
Jan 17 total       31.34
Mar 10 total        7.38
Mar 21 total        2.84
Mar 23 total        0.04
Mar 24 total       24.62
Mar 27 total        0.66
Mar 28 total       22.98
Today total       19.98

打开或关闭进程账号记录功能

[root@centos7 ~]# accton on
Turning on process accounting, file set to the default '/var/account/pacct'.
[root@centos7 ~]# accton off
Turning off process accounting.

其它工具包举例

#显示曾经登录过的用户
[root@centos7 ~]# last
root     pts/2        192.168.1.93     Mon Mar 29 05:57   still logged in   
root     tty1                          Mon Mar 29 05:31   still logged in   
root     pts/1        192.168.1.93     Mon Mar 29 05:12 - 07:56  (02:44)    
root     pts/1        192.168.1.93     Mon Mar 29 05:08 - 05:11  (00:02)    
root     pts/0        192.168.1.93     Mon Mar 29 05:00 - 07:08  (02:08)    
root     pts/1        192.168.1.93     Sun Mar 28 23:42 - 04:59  (05:17)    
root     pts/0        192.168.1.93     Sun Mar 28 12:03 - 05:00  (16:56)    
root     pts/0        192.168.1.93     Sun Mar 28 10:38 - 12:00  (01:22)    
root     pts/0        192.168.1.93     Sun Mar 28 02:10 - 09:22  (07:12)    
root     pts/0        192.168.1.93     Sun Mar 28 02:07 - 02:10  (00:02)    
root     pts/1        192.168.1.93     Sun Mar 28 01:35 - 01:36  (00:00)    
root     pts/0        192.168.1.93     Sat Mar 27 23:20 - 02:07  (02:47)    
reboot   system boot  3.10.0-1127.18.2 Sat Mar 27 04:58 - 08:19 (2+03:20)   
root     pts/0        192.168.1.93     Wed Mar 24 21:09 - crash (2+07:49)   
root     pts/1        192.168.1.93     Wed Mar 24 15:15 - 15:54  (00:39)    
root     pts/0        192.168.1.93     Wed Mar 24 14:49 - 21:08  (06:19)    
root     pts/0        192.168.1.93     Wed Mar 24 05:44 - 14:48  (09:04)    
root     pts/0        192.168.1.93     Wed Mar 24 04:10 - 05:43  (01:33)    
root     pts/0        192.168.1.93     Tue Mar 23 23:57 - 04:10  (04:12)    
reboot   system boot  3.10.0-1127.18.2 Tue Mar 23 23:56 - 08:19 (5+08:22)   
root     pts/0        192.168.1.93     Tue Mar 23 23:27 - crash  (00:29)    
reboot   system boot  3.10.0-1127.18.2 Mon Mar 22 07:22 - 08:19 (7+00:56)   
root     pts/0        192.168.1.93     Sun Mar 21 10:31 - 12:15  (01:43)    
root     pts/0        192.168.1.93     Sun Mar 21 10:07 - 10:30  (00:23)    
root     pts/0        192.168.1.93     Sun Mar 21 01:29 - 02:12  (00:43)    
reboot   system boot  3.10.0-1127.18.2 Sun Mar 21 01:28 - 08:19 (8+06:50)   
root     pts/0        192.168.1.93     Wed Mar 10 11:20 - 14:32  (03:12)    
root     pts/1        192.168.1.93     Wed Mar 10 10:39 - 11:11  (00:32)    
root     pts/1        192.168.1.93     Wed Mar 10 09:14 - 10:38  (01:24)    
root     pts/1        192.168.1.93     Wed Mar 10 09:04 - 09:05  (00:00)    
root     pts/0        192.168.1.93     Wed Mar 10 09:00 - 11:13  (02:13)    
reboot   system boot  3.10.0-1127.18.2 Mon Mar  8 10:20 - 08:19 (20+20:58)  
root     pts/2        centos7          Sun Jan 17 14:30 - 15:31  (01:00)    
root     pts/0        192.168.1.93     Sun Jan 17 14:26 - 15:31  (01:04)    
root     pts/0        192.168.1.93     Sun Jan 17 12:44 - 14:01  (01:16)    
root     tty1                          Sun Jan 17 12:43 - crash (49+21:37)  
root     pts/1        192.168.1.93     Sun Jan 17 08:32 - 14:42  (06:10)    
root     pts/0        192.168.1.93     Sun Jan 17 08:26 - 10:31  (02:05)    
root     pts/0        192.168.1.93     Sat Jan 16 19:34 - 08:25  (12:51)    
root     pts/0        192.168.1.93     Sat Jan 16 16:17 - 19:33  (03:16)    
root     pts/0        192.168.1.93     Sat Jan 16 15:43 - 16:15  (00:31)    
root     pts/0        192.168.1.93     Sat Jan 16 10:28 - 15:43  (05:14)    
root     pts/0        192.168.1.93     Sat Jan 16 09:51 - 10:27  (00:36)    
root     pts/0        192.168.1.93     Sat Jan 16 03:35 - 09:51  (06:15)    
root     pts/0        192.168.1.93     Fri Jan 15 22:46 - 03:23  (04:37)    
reboot   system boot  3.10.0-1127.18.2 Thu Jan 14 05:41 - 08:19 (74+01:37)  
root     pts/0        192.168.1.93     Sat Jan  2 08:42 - 11:04  (02:22)    
root     pts/0        192.168.1.93     Sat Jan  2 06:42 - 08:41  (01:59)    
root     tty1                          Sat Jan  2 06:22 - crash (11+23:19)  
reboot   system boot  3.10.0-1127.18.2 Sat Jan  2 06:21 - 08:19 (86+00:58)  
root     pts/0        192.168.1.93     Thu Dec 24 22:33 - 22:39  (00:06)    
root     tty1                          Thu Dec 24 22:29 - 22:40  (00:10)    
reboot   system boot  3.10.0-1127.18.2 Thu Dec 24 22:28 - 22:40  (00:12)    
root     pts/1        192.168.1.93     Sun Aug 30 03:58 - down   (00:44)    
root     pts/0        192.168.1.93     Sun Aug 30 03:29 - down   (01:13)    
root     tty1                          Sun Aug 30 03:29 - 04:42  (01:13)    
reboot   system boot  3.10.0-1127.18.2 Sun Aug 30 03:28 - 04:42  (01:14)    
root     pts/1        192.168.1.93     Thu Aug 20 11:20 - crash (9+16:08)   
root     pts/0        192.168.1.93     Thu Aug 20 10:46 - 11:39  (00:53)    
reboot   system boot  3.10.0-1062.el7. Thu Aug 20 10:45 - 04:42 (9+17:57)   
root     tty1                          Thu Aug 20 10:42 - 10:45  (00:02)    
reboot   system boot  3.10.0-1062.el7. Thu Aug 20 10:42 - 10:45  (00:03)    

wtmp begins Thu Aug 20 10:42:00 2020

#显示已执行过的命令
[root@centos7 ~]# lastcomm
last                   root     pts/2      0.01 secs Mon Mar 29 08:19
bash              F    root     pts/2      0.00 secs Mon Mar 29 08:19
cat                    root     pts/2      0.00 secs Mon Mar 29 08:18
accton           S     root     pts/2      0.00 secs Mon Mar 29 08:18
accton                 root     pts/2      0.00 secs Mon Mar 29 08:17
accton           S     root     pts/2      0.00 secs Mon Mar 29 08:17
accton                 root     pts/2      0.00 secs Mon Mar 29 08:17
accton           S     root     pts/2      0.00 secs Mon Mar 29 08:17
accton                 root     pts/2      0.00 secs Mon Mar 29 08:17
ac                     root     pts/2      0.00 secs Mon Mar 29 08:15
ac                     root     pts/2      0.00 secs Mon Mar 29 08:15
ac                     root     pts/2      0.00 secs Mon Mar 29 08:13
ac                     root     pts/2      0.00 secs Mon Mar 29 08:13
ac                     root     pts/2      0.00 secs Mon Mar 29 08:13
kworker/0:2       F    root     __         0.00 secs Mon Mar 29 08:07
kworker/0:0       F    root     __         2.36 secs Mon Mar 29 07:20
systemd-cgroups  S     root     __         0.00 secs Mon Mar 29 08:10
crond            SF    root     __         0.01 secs Mon Mar 29 08:10
sadc             S     root     __         0.01 secs Mon Mar 29 08:10
date                   root     __         0.00 secs Mon Mar 29 08:10
date                   root     __         0.00 secs Mon Mar 29 08:10
kworker/0:2       F    root     __         0.22 secs Mon Mar 29 07:47
accton                 root     pts/2      0.00 secs Mon Mar 29 08:03
systemd-cgroups  S     root     __         0.00 secs Mon Mar 29 08:01
crond            SF    root     __         0.02 secs Mon Mar 29 08:01
run-parts              root     __         0.00 secs Mon Mar 29 08:01
logger                 root     __         0.00 secs Mon Mar 29 08:01
basename               root     __         0.00 secs Mon Mar 29 08:01
awk                    root     __         0.00 secs Mon Mar 29 08:01
0anacron               root     __         0.00 secs Mon Mar 29 08:01
date                   root     __         0.00 secs Mon Mar 29 08:01
cat                    root     __         0.00 secs Mon Mar 29 08:01
logger                 root     __         0.00 secs Mon Mar 29 08:01
basename               root     __         0.00 secs Mon Mar 29 08:01
run-parts         F    root     __         0.00 secs Mon Mar 29 08:01
systemctl        S     root     pts/2      0.00 secs Mon Mar 29 08:00
systemctl        S     root     pts/2      0.00 secs Mon Mar 29 08:00
pkttyagent           X root     pts/2      0.03 secs Mon Mar 29 08:00
systemd-tty-ask        root     pts/2      0.01 secs Mon Mar 29 08:00
systemd-cgroups  S     root     __         0.00 secs Mon Mar 29 08:00
accton           S     root     __         0.00 secs Mon Mar 29 08:00

#输出所有的帐户活动信息
[root@centos7 ~]# sa
      42      76.03re       0.04cp         0avio     15376k
      11      52.42re       0.04cp         0avio     22963k   ***other*
       2      23.59re       0.00cp         0avio         0k   kworker/0:2*
       2       0.00re       0.00cp         0avio     32128k   crond*
       8       0.00re       0.00cp         0avio       795k   accton
       5       0.01re       0.00cp         0avio      1092k   ac
       3       0.00re       0.00cp         0avio      2168k   systemd-cgroups
       3       0.00re       0.00cp         0avio     27024k   date
       2       0.01re       0.00cp         0avio     33728k   systemctl
       2       0.00re       0.00cp         0avio     27024k   cat
       2       0.00re       0.00cp         0avio     27008k   logger
       2       0.00re       0.00cp         0avio     27008k   basename
       3

这个命令所包含的这些工具包,功能还是非常强大的,在日常工作中可以很大程度提高我们的工作效率,解决一些问题。

查看原文

赞 2 收藏 1 评论 0

民工哥 发布了文章 · 4月14日

每天学一个 Linux 命令(114):ldd

命令简介

ldd 命令打印程序和库的共享库依赖项。注意:ldd 不是一个可执行程序,而只是一个 Shell 脚本。

语法格式

ldd [OPTION]... FILE...

选项说明

--version  #打印指令版本号
-v  #打印所有相关信息
-u  #打印未使用的直接依赖
-d  #执行重定位和报告任何丢失的对象
-r  #执行数据对象和函数的重定位,并且报告任何丢失的对象和函数
--help  #显示帮助信息

应用举例

打印版本信息

[root@centos7 ~]# ldd --version
ldd (GNU libc) 2.17
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.

打印 /bin/bash 的共享库依赖项

[root@centos7 ~]# ldd /bin/bash
    linux-vdso.so.1 =>  (0x00007ffd15ca8000)
    libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00007f7343eab000)
    libdl.so.2 => /lib64/libdl.so.2 (0x00007f7343ca7000)
    libc.so.6 => /lib64/libc.so.6 (0x00007f73438d9000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f73440d5000)

查看原文

赞 1 收藏 1 评论 0

民工哥 发布了文章 · 4月14日

每天学一个 Linux 命令(113):dnf

命令简介

DNF (Dandified Yum) 是新一代的RPM软件包管理器。

DNF 包管理器克服了 YUM 包管理器的一些瓶颈,提升了包括用户体验,内存占用,依赖分析,运行速度等多方面的内容。DNF 使用 RPM, libsolv 和 hawkey 库进行包管理操作,Fedora22 已经默认使用 DNF。

[root@centos7 ~]# dnf
-bash: dnf: command not found
#CentOS 安装
#安装 epel-release 依赖:
[root@centos7 ~]# yum install epel-release
 
#安装 DNF 包:
[root@centos7 ~]# yum install dnf

配置文件所在目录 :/etc/dnf/dnf.conf

为什么要舍弃 Yum 而用 DNF?

有三个主要原因:

  • Yum 没有 API 文档。这意味着开发者需要做更多的工作。Yum 开发者写一个调用函数都需要查看 Yum 的代码库,使开发变得缓慢。
  • Fedora 将会过渡到 Python3,但 Yum 却没有这个能力,而 DNF 既可以使用 Python2,也可以在 Python3 环境下运行。
  • 依赖解决能力长期是 Fedora 软件包管理的阿喀硫斯之踵。DNF 使用基于 SAT 的依赖问题解决方法,与 SUSE 和 OpenSUSE 的 Zypper 类似。

语法格式

dnf [options] [command] [package ...]

选项说明

#与YUM 基本保持一致,少数用法有区别
--version  #查看DNF包管理器版本
help       #查看所有的DNF命令及其用途
help <command>  #获取命令的使用帮助
history         #查看 DNF 命令的执行历史
repolist        #查看系统中可用的DNF软件库
search <package>     #搜索软件库中的RPM包
list installed       #列出所有安装的RPM包
list available       #列出所有可安装的RPM包
info <package>       #查看软件包详情
provides <file>      #查找某一文件的提供者
install <package>    #安装软件包及其所需的所有依赖
update <package>     #升级软件包
remove <package>     #删除软件包
reinstall <package>  #重新安装特定软件包
distro-sync   #更新软件包到最新的稳定发行版
check-update  #检查系统所有软件包的更新
update        #升级所有系统软件包
clean all     #删除缓存的无用软件包

应用举例

DNF 安装、卸载

[root@centos7 ~]# dnf install package
[root@centos7 ~]# dnf remove  package

#升级软件
[root@centos7 ~]# dnf update
 
#升级系统
[root@centos7 ~]# dnf upgrade
 
#清除 RPM 包缓存
[root@centos7 ~]# dnf clean packages

查看 dnf 版本:

[root@centos7 ~]# dnf --version
4.0.9
  Installed: dnf-0:4.0.9.2-2.el7_9.noarch at Mon 29 Mar 2021 09:58:48 AM EST
  Built    : CentOS BuildSystem <http://bugs.centos.org> at Wed 07 Apr 2021 03:52:38 PM EST

  Installed: rpm-0:4.11.3-43.el7.x86_64 at Thu 20 Aug 2020 02:49:31 PM EST
  Built    : CentOS BuildSystem <http://bugs.centos.org> at Wed 01 Apr 2020 04:21:52 AM EST

查看原文

赞 1 收藏 1 评论 0

民工哥 发布了文章 · 4月13日

Kubernetes 之 YAML 语法

YAML 是一种非常简洁/强大/专门用来写配置文件的语言!

YAML 全称是 ”YAML Ain’t a Markup Language” 的递归缩写,该语言的设计参考了 JSON / XML 和 SDL 等语言,强调以数据为中心,简洁易读,编写简单。

image.png

YAML 语法特性

学过编程的人理解起来应该非常容易
image.png

语法特点

  • 大小写敏感
  • 通过缩进表示层级关系
  • 禁止使用tab缩进,只能使用空格键
  • 缩进的空格数目不重要,只要相同层级左对齐
  • 使用#表示注释
# yaml
languages:
    - Ruby
    - Perl
    - Python
websites:
    YAML: yaml.org
    Ruby: ruby-lang.org
    Python: python.org
    Perl: use.perl.org

# Json
{
    languages: [
        'Ruby',
        'Perl',
        'Python'
    ],
    websites: {
        YAML: 'yaml.org',
        Ruby: 'ruby-lang.org',
        Python: 'python.org',
        Perl: 'use.perl.org'
    }
}

数据结构

  • 对象: 键值对的字典 -数组: 一组按次序排列的列表 -纯量: 单个的且不可再分的值
# 纯量
hello

# 数组
- Cat
- Dog
- Goldfish

# 对象
animal: pets
  • 引号区别
  • 单引号(''): 特殊字符作为普通字符串处理
  • 双引号(""): 特殊字符作为本身想表示的意思

    # 单引号
    name: 'Hi,\nTom'

双引号

name: "Hi,\nTom"

## 内置类型列表
# YAML允许使用个感叹号(!)强制转换数据类型
# 单叹号通常是自定义类型,双叹号是内置类型
money: !!str
123

date: !Boolean
true

image.png

YAML 中的纯量

纯量是最基本的且不可再分的值

  • 字符串
# 不适用引号
name: Tom

# 使用单引号
name: 'Tom'

# 使用双引号
name: "Tom"
  • 布尔值
debug: true
debug: false
  • 数字
12       # 十进制整数
014      # 八进制整数
0xC      #十六进制整数
13.4     #浮点数
1.2e+34  #指数
.inf     #无穷大
  • Null
date: ~
date: null
  • 时间
# 使用iso-8601标准表示日期
date: 2018-01-01t16:59:43.10-05:00

YAML 特殊类型

日常使用中基本不会用到的类型

文本块

# 注意“|”与文本之间须另起一行
# 使用|标注的文本内容缩进表示的块,可以保留块中已有的回车换行
value: |
  hello
  world!

# 输出结果
# hello 换行 world!

# +表示保留文字块末尾的换行
# -表示删除字符串末尾的换行
value: |
hello

value: |-
hello

value: |+
hello

# 输出结果
# hello\n hello hello\n\n

# 注意“>”与文本之间的空格
# 使用>标注的文本内容缩进表示的块,将块中回车替换为空格最终连接成一行
value: > hello
world!

# 输出结果
# hello 空格 world!

锚点与引用

# 复制代码注意*引用部分不能追加内容
# 使用&定义数据锚点,即要复制的数据
# 使用*引用锚点数据,即数据的复制目的地
name: &a yaml
book: *a
books:
   - java
   - *a
   - python

# 输出结果
book: yaml
books:[java, yaml, python]

YAML 实例说明

光说不练假把式 => JS-Yaml 官网实例地址 https://nodeca.github.io/js-yaml

---
# Collection Types #############################################################
################################################################################

# http://yaml.org/type/map.html -----------------------------------------------#

map:
  # Unordered set of key: value pairs.
  Block style: !!map
    Clark: Evans
    Ingy: döt Net
    Oren: Ben-Kiki
  Flow style: !!map { Clark: Evans, Ingy: döt Net, Oren: Ben-Kiki }

# http://yaml.org/type/omap.html ----------------------------------------------#

omap:
  # Explicitly typed ordered map (dictionary).
  Bestiary: !!omap
    - aardvark: African pig-like ant eater. Ugly.
    - anteater: South-American ant eater. Two species.
    - anaconda: South-American constrictor snake. Scaly.
    # Etc.
  # Flow style
  Numbers: !!omap [one: 1, two: 2, three: 3]

# http://yaml.org/type/pairs.html ---------------------------------------------#

pairs:
  # Explicitly typed pairs.
  Block tasks: !!pairs
    - meeting: with team.
    - meeting: with boss.
    - break: lunch.
    - meeting: with client.
  Flow tasks: !!pairs [meeting: with team, meeting: with boss]

# http://yaml.org/type/set.html -----------------------------------------------#

set:
  # Explicitly typed set.
  baseball players: !!set
    ? Mark McGwire
    ? Sammy Sosa
    ? Ken Griffey
  # Flow style
  baseball teams: !!set { Boston Red Sox, Detroit Tigers, New York Yankees }

# http://yaml.org/type/seq.html -----------------------------------------------#

seq:
  # Ordered sequence of nodes
  Block style: !!seq
    - Mercury # Rotates - no light/dark sides.
    - Venus # Deadliest. Aptly named.
    - Earth # Mostly dirt.
    - Mars # Seems empty.
    - Jupiter # The king.
    - Saturn # Pretty.
    - Uranus # Where the sun hardly shines.
    - Neptune # Boring. No rings.
    - Pluto # You call this a planet?
  Flow style: !!seq [
      Mercury,
      Venus,
      Earth,
      Mars, # Rocks
      Jupiter,
      Saturn,
      Uranus,
      Neptune, # Gas
      Pluto,
    ] # Overrated

# Scalar Types #################################################################
################################################################################

# http://yaml.org/type/bool.html ----------------------------------------------#

bool:
  - true
  - True
  - TRUE
  - false
  - False
  - FALSE

# http://yaml.org/type/float.html ---------------------------------------------#

float:
  canonical: 6.8523015e+5
  exponentioal: 685.230_15e+03
  fixed: 685_230.15
  sexagesimal: 190:20:30.15
  negative infinity: -.inf
  not a number: .NaN

# http://yaml.org/type/int.html -----------------------------------------------#

int:
  canonical: 685230
  decimal: +685_230
  octal: 02472256
  hexadecimal: 0x_0A_74_AE
  binary: 0b1010_0111_0100_1010_1110
  sexagesimal: 190:20:30

# http://yaml.org/type/merge.html ---------------------------------------------#

merge:
  - &CENTER { x: 1, y: 2 }
  - &LEFT { x: 0, y: 2 }
  - &BIG { r: 10 }
  - &SMALL { r: 1 }

  # All the following maps are equal:

  - # Explicit keys
    x: 1
    y: 2
    r: 10
    label: nothing

  - # Merge one map
    <<: *CENTER
    r: 10
    label: center

  - # Merge multiple maps
    <<: [*CENTER, *BIG]
    label: center/big

  - # Override
    <<: [*BIG, *LEFT, *SMALL]
    x: 1
    label: big/left/small

# http://yaml.org/type/null.html ----------------------------------------------#

null:
  # This mapping has four keys,
  # one has a value.
  empty:
  canonical: ~
  english: null
  ~: null key
  # This sequence has five
  # entries, two have values.
  sparse:
    - ~
    - 2nd entry
    -
    - 4th entry
    - Null

# http://yaml.org/type/str.html -----------------------------------------------#

string: abcd

# http://yaml.org/type/timestamp.html -----------------------------------------#

timestamp:
  canonical: 2001-12-15T02:59:43.1Z
  valid iso8601: 2001-12-14t21:59:43.10-05:00
  space separated: 2001-12-14 21:59:43.10 -5
  no time zone (Z): 2001-12-15 2:59:43.10
  date (00:00:00Z): 2002-12-14

# JavaScript Specific Types ####################################################
################################################################################

# https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/RegExp

regexp:
  simple: !!js/regexp foobar
  modifiers: !!js/regexp /foobar/mi

# https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/undefined

undefined: !!js/undefined ~

# https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function

function: !!js/function >
  function foobar() {
    return 'Wow! JS-YAML Rocks!';
  }

# Custom types #################################################################
################################################################################

# JS-YAML allows you to specify a custom YAML types for your structures.
# This is a simple example of custom constructor defined in `js/demo.js` for
# custom `!sexy` type:
#
# var SexyYamlType = new jsyaml.Type('!sexy', {
#   kind: 'sequence',
#   construct: function (data) {
#     return data.map(function (string) { return 'sexy ' + string; });
#   }
# });
#
# var SEXY_SCHEMA = jsyaml.Schema.create([ SexyYamlType ]);
#
# result = jsyaml.load(yourData, { schema: SEXY_SCHEMA });

foobar: !sexy
  - bunny
  - chocolate

作者: Escape
链接: https://www.escapelife.site/p...

查看原文

赞 1 收藏 1 评论 0

民工哥 发布了文章 · 4月13日

每天学一个 Linux 命令(112):vmstat

命令简介

vmstat 命令用于虚拟内存统计。vmstat 报告有关进程,内存,分页,块IO,陷阱,磁盘和CPU活动的信息。

语法格式

vmstat [options] [delay [count]]

选项说明

-a  #显示活动内页
-f  #显示启动后创建的进程总数
-m  #显示slab信息
-h  #显示帮助并退出
-n  #头信息仅显示一次
-s  #以表格方式显示事件计数器和内存状态
-d  #报告磁盘状态
-p  #显示指定的硬盘分区状态
-S  #输出信息的单位
-V  #显示版本信息并退出

应用举例

显示所有信息

[root@centos7 ~]# vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0      0 568632   2108 311348    0    0     7     1   50   38  2  1 98  0  0
#1秒刷新一次
[root@centos7 ~]# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0      0 568780   2108 311380    0    0     7     1   50   38  2  1 98  0  0
 0  0      0 568756   2108 311380    0    0     0     0   20   20  0  0 100  0  0
 0  0      0 568756   2108 311380    0    0     0     0   25   25  0  1 99  0  0
 0  0      0 568756   2108 311380    0    0     0     0   17   14  0  0 100  0  0
 0  0      0 568756   2108 311380    0    0     0     0   20   18  0  0 100  0  0
 0  0      0 568756   2108 311380    0    0     0     0   16   12  0  0 100  0  0
 0  0      0 568756   2108 311380    0    0     0     0   25   25  0  1 99  0  0

结果的字段说明

#Procs(进程)
r: 运行队列中进程数量
b: 等待IO的进程数量

#Memory(内存)
swpd: 使用虚拟内存大小
free: 空闲物理内存大小
buff: 用作缓冲的内存大小
cache: 用作缓存的内存大小

#Swap
si: 每秒从交换区写到内存的大小,由磁盘调入内存
so: 每秒写入交换区的内存大小,由内存调入磁盘
 
#IO(现在的Linux版本块的大小为1kb)
bi: 每秒读取的块数
bo: 每秒写入的块数
 
#system(系统)
in: 每秒中断数,包括时钟中断
cs: 每秒上下文切换数
 
#CPU(以百分比表示)
 
us: 用户进程执行时间百分比(user time),us的值比较高时,说明用户进程消耗的CPU时间多。
sy: 内核系统进程执行时间百分比(system time),sy的值高时,说明系统内核消耗的CPU资源多。
wa: IO等待时间百分比,wa的值高时,说明IO等待比较严重。
 
#id: 空闲时间百分比

显示系统启动后创建的进程数

[root@centos7 ~]# vmstat -f
         5303 forks

查看磁盘状态

[root@centos7 ~]# vmstat -d
disk- ------------reads------------ ------------writes----------- -----IO------
       total merged sectors      ms  total merged sectors      ms    cur    sec
fd0        0      0       0       0      0      0       0       0      0      0
sda     8001     12  603239   68687   1841    278   64871  192251      0     91
sdb       92      0    5184     563      0      0       0       0      0      0
sr0       18      0    2056     245      0      0       0       0      0      0
dm-0    5949      0  579134   67305   2115      0   60775  227833      0     91
dm-1      88      0    4408     154      0      0       0       0      0      0

显示指定磁盘分区的状态

[root@centos7 ~]# vmstat -p /dev/sda1
sda1          reads   read sectors  writes    requested writes
                1864      12369          4       4096
[root@centos7 ~]# vmstat -p /dev/sda2
sda2          reads   read sectors  writes    requested writes
                6107     587782       1846      60879
[root@centos7 ~]# vmstat -p /dev/sdb
partition was not found

到今天为止,《每天学习一个Linux系统命令》推送了112篇文章了,希望能对大家有所帮助,系统命令也是系统入门后的第一步,也是非常重要的一步,多练、多操作、多总结,写文不易,如有帮助,请大家点赞与转发分享支持一下民工哥。

查看原文

赞 2 收藏 1 评论 0

民工哥 发布了文章 · 4月13日

每天学一个 Linux 命令(111):mpstat

命令简介

mpstat(Multi-Processor Statistics) 命令用于显示各个可用CPU的状态统计。是一个实时监控工具,与vmstat类似,但只能监控CPU的整体性能状态。

[root@centos7 ~]# mpstat
-bash: mpstat: command not found
[root@centos7 ~]# yum install sysstat -y

语法格式

mpstat [ options ]

选项说明

-P  #指定CPU编号

应用举例

列出端口

[root@centos7 ~]# mpstat
Linux 3.10.0-1127.18.2.el7.x86_64 (centos7)     03/28/2021     _x86_64_    (1 CPU)

11:14:29 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
11:14:29 AM  all    1.61    0.00    0.48    0.05    0.00    0.07    0.00    0.00    0.00   97.79

字段说明

%user      
#在internal时间段里,用户态的CPU时间(%),不包含nice值为负进程  (usr/total)*100
%nice      
#在internal时间段里,nice值为负进程的CPU时间(%)(nice/total)*100
%sys       
#在internal时间段里,内核时间(%)(system/total)*100
%iowait    
#在internal时间段里,硬盘IO等待时间(%) (iowait/total)*100
%irq         
#在internal时间段里,硬中断时间(%)(irq/total)*100
%soft       
#在internal时间段里,软中断时间(%)(softirq/total)*100
%idle       
#在internal时间段里,CPU除去等待磁盘IO操作外的因为任何原因而空闲的时间闲置时间(%) (idle/total)*100

查看原文

赞 1 收藏 1 评论 0

民工哥 发布了文章 · 4月12日

每天学一个 Linux 命令(99):nohup

命令简介

nohup 命令用于将进程放后台运行(不挂断)。

命令语法

nohup Command [ Arg … ] [ & ]

选项说明

--help    #打印帮助信息并退出
--version  #打印版本信息并退出

应用举例

后台运行

[root@centos7 ~]# nohup java -server -Xms128M -Xmx512M -XX:MetaspaceSize=128M -jar test.jar $1 $2 $3 &

执行test.sh 脚本,并重定向输入到 test.log 文件

[root@centos7 ~]# nohup /scripts/test.sh > test.log 2>&1 &

2>&1 解释
#将标准错误 2 重定向到标准输出 &1 ,标准输出 &1 再被重定向输入到 test.log 文件中。
0 – stdin (standard input,标准输入)
1 – stdout (standard output,标准输出)
2 – stderr (standard error,标准错误输出)

查看原文

赞 2 收藏 2 评论 0

民工哥 发布了文章 · 4月12日

每天学一个 Linux 命令(107):sar

命令简介

sar命令用于全面地获取系统的CPU、运行队列、磁盘 I/O、分页(交换区)、内存、 CPU中断和网络等性能数据。

语法格式

sar -[ options ] time_interval number_of_tines_to_display

选项说明

-A  #汇总所有的报告
-a  #查看文件读写使用情况
-B  #查看附加的缓存的使用情况
-b  #查看缓存的使用情况
-c  #查看系统调用的使用情况
-d  #查看磁盘的使用情况
-g  #查看串口的使用情况
-h  #查看关于buffer使用的统计数据
-m  #查看IPC消息队列和信号量的使用情况
-n  #查看命名cache的使用情况
-p  #查看调页活动的使用情况
-q  #查看平均负载
-R  #查看进程的活动情况
-r  #查看没有使用的内存页面和硬盘块
-u  #查看CPU的利用率
-v  #查看进程、i节点、文件和锁表状态
-w  #查看系统交换活动状况
-y  #查看TTY设备活动状况

应用举例

查看内存交换空间的使用率信息

[root@centos7 ~]# sar -r
Linux 3.10.0-1127.18.2.el7.x86_64 (centos7)  03/28/2021  _x86_64_ (1 CPU)
11:10:02 AM kbmemfree kbmemused  %memused kbbuffers  kbcached  kbcommit   %commit  kbactive   kbinact   kbdirty
11:20:01 AM    532544    463140     46.51      2108    313176    232184      7.51    216412    134456         0
11:30:01 AM    532504    463180     46.52      2108    313180    232184      7.51    216436    134412         0
Average:       532524    463160     46.52      2108    313178    232184      7.51    216424    134434         0

输出的结果字段说明

kbmemfree  #空闲物理内存量
kbmemused  #使用中的物理内存量
%memused   #物理内存量使用率
kbbuffers  #内核中作为缓冲区使用的物理内存容量
kbcacheed  #内核中作为缓存使用的物理内存容量
kbswpfree  #交换区的空闲容量
kbswpused  #使用中的交换区容量

查看CPU使用率

[root@centos7 ~]# sar -u
Linux 3.10.0-1127.18.2.el7.x86_64 (centos7)  03/28/2021  _x86_64_ (1 CPU)
11:10:02 AM     CPU     %user     %nice   %system   %iowait    %steal     %idle
11:20:01 AM     all      0.03      0.00      0.18      0.02      0.00     99.77
11:30:01 AM     all      0.03      0.00      0.17      0.02      0.00     99.78
Average:        all      0.03      0.00      0.18      0.02      0.00     99.77

查看平均负载

[root@centos7 ~]# sar -q
Linux 3.10.0-1127.18.2.el7.x86_64 (centos7)  03/28/2021  _x86_64_ (1 CPU)
11:10:02 AM   runq-sz  plist-sz   ldavg-1   ldavg-5  ldavg-15   blocked
11:20:01 AM         1       108      0.00      0.01      0.05         0
11:30:01 AM         1       108      0.00      0.01      0.05         0
Average:            1       108      0.00      0.01      0.05         0

查看页面交换发生状况

[root@centos7 ~]# sar -w
Linux 3.10.0-1127.18.2.el7.x86_64 (centos7)  03/28/2021  _x86_64_ (1 CPU)
11:10:02 AM    proc/s   cswch/s
11:20:01 AM      0.02     19.10
11:30:01 AM      0.03     19.92
11:40:01 AM      0.02     19.45
Average:         0.02     19.49

查看I/O和传送速率的统计信息

[root@centos7 ~]# sar -b
Linux 3.10.0-1127.18.2.el7.x86_64 (centos7)  03/28/2021  _x86_64_ (1 CPU)
11:10:02 AM       tps      rtps      wtps   bread/s   bwrtn/s
11:20:01 AM      0.06      0.00      0.06      0.00      0.74
11:30:01 AM      0.03      0.00      0.03      0.00      0.40
Average:         0.05      0.00      0.05      0.00      0.57

输出字段说明

tps       #每秒钟物理设备的 I/O 传输总量 
rtps      #每秒钟从物理设备读入的数据总量 
wtps      #每秒钟向物理设备写入的数据总量 
bread/s   #每秒钟从物理设备读入的数据量,单位为 块/s 
bwrtn/s   #每秒钟向物理设备写入的数据量,单位为 块/s

查看网络状态信息

[root@centos7 ~]# sar -n DEV
Linux 3.10.0-1127.18.2.el7.x86_64 (centos7)  03/28/2021  _x86_64_ (1 CPU)
11:10:02 AM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s
11:20:01 AM        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00
11:20:01 AM     ens33      0.83      0.54      0.06      0.05      0.00      0.00      0.00
11:30:01 AM        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00
11:30:01 AM     ens33      1.07      0.69      0.08      0.06      0.00      0.00      0.00
11:40:01 AM        lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00
11:40:01 AM     ens33      0.91      0.60      0.07      0.05      0.00      0.00      0.00
Average:           lo      0.00      0.00      0.00      0.00      0.00      0.00      0.00
Average:        ens33      0.94      0.61      0.07      0.05      0.00      0.00 

image

查看原文

赞 1 收藏 1 评论 0

民工哥 发布了文章 · 4月12日

每天学一个 Linux 命令(109):iostat

命令简介

iostat 命令用于统计系统IO状态信息。

语法格式

iostat [options]

选项说明

-c  #仅显示CPU使用情况
-d  #仅显示设备利用率
-k  #显示状态以千字节每秒为单位,而不使用块每秒
-m  #显示状态以兆字节每秒为单位
-p  #仅显示块设备和所有被使用的其他分区的状态
-t  #显示每个报告产生时的时间
-V  #显示版号并退出
-x  #显示扩展状态

应用举例

查看指定设备的IO状态信息

[root@centos7 ~]# iostat -x /dev/sda1
Linux 3.10.0-1127.18.2.el7.x86_64 (centos7)  03/28/2021  _x86_64_ (1 CPU)
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           1.59    0.00    0.55    0.05    0.00   97.81
Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
sda1              0.00     0.00    0.04    0.00     0.15     0.05     8.82     0.00    1.07    0.73   63.50   1.02   0.00

结果字段说明

Device  #监测设备名称
rrqm/s  #每秒需要读取需求的数量
wrqm/s  #每秒需要写入需求的数量
r/s     #每秒实际读取需求的数量
w/s     #每秒实际写入需求的数量
rsec/s  #每秒读取区段的数量
wsec/s  #每秒写入区段的数量
rkB/s   #每秒实际读取的大小,单位为KB
wkB/s   #每秒实际写入的大小,单位为KB
avgrq-sz  #需求的平均大小区段
avgqu-sz  #需求的平均队列长度
await     #等待I/O平均的时间(milliseconds)
svctm     #I/O需求完成的平均时间
%util     #被I/O需求消耗的CPU百分比

系统整体IO状态信息

[root@centos7 ~]# iostat
Linux 3.10.0-1127.18.2.el7.x86_64 (centos7)  03/28/2021  _x86_64_ (1 CPU)
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           1.58    0.00    0.55    0.05    0.00   97.82
Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
sda               0.25         7.39         1.84     316339      78930
sdb               0.00         0.06         0.00       2592          0
scd0              0.00         0.02         0.00       1028          0
dm-0              0.21         7.11         1.80     304267      76862
dm-1              0.00         0.05         0.00       2204          0

其它实例

#只显示CPU的IO状态
[root@centos7 ~]# iostat -c
Linux 3.10.0-1127.18.2.el7.x86_64 (centos7)  03/28/2021  _x86_64_ (1 CPU)
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           1.58    0.00    0.55    0.05    0.00   97.82
#只显示设备的使用率状态
[root@centos7 ~]# iostat -d
Linux 3.10.0-1127.18.2.el7.x86_64 (centos7)  03/28/2021  _x86_64_ (1 CPU)
Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
sda               0.25         7.38         1.84     316339      78930
sdb               0.00         0.06         0.00       2592          0
scd0              0.00         0.02         0.00       1028          0
dm-0              0.21         7.09         1.79     304267      76862
dm-1              0.00         0.05         0.00       2204          0
#以千字节每秒为单位显示
[root@centos7 ~]# iostat -k
Linux 3.10.0-1127.18.2.el7.x86_64 (centos7)  03/28/2021  _x86_64_ (1 CPU)
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           1.58    0.00    0.55    0.05    0.00   97.82
Device:            tps    kB_read/s    kB_wrtn/s    kB_read    kB_wrtn
sda               0.25         7.37         1.84     316339      78930
sdb               0.00         0.06         0.00       2592          0
scd0              0.00         0.02         0.00       1028          0
dm-0              0.21         7.09         1.79     304267      76862
dm-1              0.00         0.05         0.00       2204          0
#以兆字节每秒为单位
[root@centos7 ~]# iostat -m
Linux 3.10.0-1127.18.2.el7.x86_64 (centos7)  03/28/2021  _x86_64_ (1 CPU)
avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           1.58    0.00    0.55    0.05    0.00   97.82
Device:            tps    MB_read/s    MB_wrtn/s    MB_read    MB_wrtn
sda               0.25         0.01         0.00        308         77
sdb               0.00         0.00         0.00          2          0
scd0              0.00         0.00         0.00          1          0
dm-0              0.21         0.01         0.00        297         75
dm-1              0.00         0.00         0.00          2          0

每天学一个 Linux 命令(106):openssl

每天学一个 Linux 命令(107):sar

每天学一个 Linux 命令(108):iptraf

查看原文

赞 1 收藏 1 评论 0

民工哥 发布了文章 · 4月12日

每天学一个 Linux 命令(110):ifstat

命令简介

ifstat 命令用于统计网络接口流量状态,能比较简单看网络流量。ifstat 可以整齐地打印出网络接口统计信息,还可以用来禁用指定的网络接口。

语法格式

ifstat [OPTIONS]

选项说明

-a  #监测能检测到的所有网络接口的状态信息
-z  #隐藏流量是无的接口
-h  #显示帮助信息
-j  #用JSON格式输出信息
-n  #关闭显示周期性出现的头部信息
-t  #在每一行的开头加一个时间戳
-T  #报告所有监测接口的全部带宽
-w  #用指定的列宽
-W  #如果内容比终端窗口的宽度还要宽就自动换行
-S  #在同一行保持状态更新(不滚动不换行)
-q  #安静模式
-v  #显示版本信息
-d  #指定一个驱动来收集状态信息

应用举例

常见应用

[root@centos7 ~]# ifstat
#kernel
Interface        RX Pkts/Rate    TX Pkts/Rate    RX Data/Rate    TX Data/Rate  
                 RX Errs/Drop    TX Errs/Drop    RX Over/Rate    TX Coll/Rate  
lo                 40261 0         40261 0         2014K 0         2014K 0      
                       0 0             0 0             0 0             0 0      
ens33             385230 0        283301 0        44144K 0        77585K 0      
                       0 14            0 0             0 0             0 0 

监控指定接口

[root@centos7 ~]# ifstat   ens33
#kernel
Interface        RX Pkts/Rate    TX Pkts/Rate    RX Data/Rate    TX Data/Rate  
                 RX Errs/Drop    TX Errs/Drop    RX Over/Rate    TX Coll/Rate  
ens33                118 0            44 0          8712 0          5414 0      
                       0 0             0 0             0 0             0 0 

每天学一个 Linux 命令(106):openssl

每天学一个 Linux 命令(107):sar

每天学一个 Linux 命令(108):iptraf

查看原文

赞 0 收藏 1 评论 0

民工哥 发布了文章 · 4月11日

Kubernetes 之 Pod 实现原理

Pod 就是最小并且最简单的 Kubernetes 对象

图片

Pod、Service、Volume 和 Namespace 是 Kubernetes 集群中四大基本对象,它们能够表示系统中部署的应用、工作负载、网络和磁盘资源,共同定义了集群的状态。Kubernetes 中很多其他的资源其实只对这些基本的对象进行了组合。

  • Pod -> 集群中的基本单元

  • Service -> 解决如何访问 Pod 里面服务的问题

  • Volume -> 集群中的存储卷

  • Namespace -> 命名空间为集群提供虚拟的隔离作用

图片

Kubernetes 有许许多多的技术概念,同时对应很多 API 对象,其中最重要的也是最基础的是 Pod 对象。Pod 是在 Kubernetes 集群中运行部署应用或服务的最小单元,它是可以支持多容器的。Pod 的设计理念是支持多个容器在一个 Pod 中共享网络地址和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。

apiVersion: v1
kind: Pod
metadata:
  name: busybox
  labels:
    app: busybox
spec:
  containers:
  restartPolicy: Always
    - name: busybox
      image: busybox
      command:
        - sleep
        - "3600"
      imagePullPolicy: IfNotPresent

Pod 的内部结构

Pod 代表着集群中运行的进程:共享网络、共享存储

在同一个 Pod 中,有几个概念特别值得关注,首先就是容器,在 Pod 中其实可以同时运行一个或者多个容器,这些容器能够共享网络、存储以及 CPU/内存等资源。

首先,我们需要知道的是,每个 Pod 都有一个特殊的被称为 “根容器” 的 Pause 容器。Pause 容器对应的镜像属于 Kubernetes 平台的一部分,通过 Pause 容器使工作在对应 Pod 的容器之间可以共享网络、共享存储。

图片

Pod 共享资源

为什么 Kubernetes 会设计出一个全新的 Pod 概念,并且有这样特殊的结构?主要是因为,使用 Pause 容器作为 Pod 根容器,以它的状态代表整个容器组的状态;其次,Pod 里的多个业务容器共享 Pause 容器的 IP 地址,共享 Pause 容器挂接的 Volume 资源。

  • 共享存储资源

可以为一个 Pod 指定多个共享的 Volume 资源。Pod 中的所有容器都可以访问共享的 volume 资源。Volume 也可以用来持久化 Pod 中的存储资源,以防容器重启后文件丢失。

  • 共享网络资源

每个 Pod 都会被分配一个唯一的 IP 地址。Pod 中的所有容器共享网络空间,包括 IP 地址和端口。Pod 内部的容器可以使用 localhost 互相通信。Pod 中的容器与外界通信时,必须分配共享网络资源,例如使用宿主机的端口映射。

图片

veth 设备的特点

一个设备收到协议栈的数据发送请求后,会将数据发送到另一个设备上去

  • veth 和其它的网络设备都一样,一端连接的是内核协议栈

  • veth 设备是成对出现的,另一端两个设备彼此相连

# 物理网卡eth0配置的IP为192.168.1.11
# 而veth0和veth1的IP分别是192.168.2.11和192.168.2.10
+----------------------------------------------------------------+
|                                                                |
|       +------------------------------------------------+       |
|       |             Newwork Protocol Stack             |       |
|       +------------------------------------------------+       |
|              ↑               ↑               ↑                 |
|..............|...............|...............|.................|
|              ↓               ↓               ↓                 |
|        +----------+    +-----------+   +-----------+           |
|        |   eth0   |    |   veth0   |   |   veth1   |           |
|        +----------+    +-----------+   +-----------+           |
|192.168.1.11  ↑               ↑               ↑                 |
|              |               +---------------+                 |
|              |         192.168.2.11     192.168.2.10           |
+--------------|-------------------------------------------------+
               ↓
         Physical Network

Pod 的网络通信

集群网络解决方案: Kubernetes + Flannel

Kubernetes 的网络模型假定了所有 Pod 都在一个直接连通的扁平的网络空间中,这在 GCE(Google Compute Engine)里面是现成的网络模型,Kubernetes 假定这个网络已经存在了。而在私有云搭建 Kubernetes 集群,就不能假定这个网络已经存在了。我们需要自己实现这个网络假设,将不同节点上的 Docker 容器之间的互相访问先打通,然后才能正常运行 Kubernetes 集群。

  • 同一个 Pod 内多个容器之前通过回环网络(lo - 127.0.0.1)进行通信

  • 各 Pod 之间的通讯,则是通过 Overlay Network 网络进行通信

  • 而 Pod 与 Service 之间的通讯,则是各节点的 iptables 或 lvs 规则

Flannel 是 CoreOS 团队针对 Kubernetes 设计的一个网络规划服务,简单来说,它的功能就是让集群中的不同节点主机创建的 Docker 容器都具有全集群唯一的虚拟 IP 地址。而且它还能在这些 IP 地址之间建立一个覆盖的网络(Overlay Network),通过这个覆盖网络,将数据包原封不动地传递给目标容器内。

图片

图片

不同情况下的网络通信方式

  • 同一个 Pod 内部通讯:

  • 同一个 Pod 共享同一个网络命名空间,共享同一个 Linux 协议栈。

  • 不同 Pod 之间通讯:

  • Pod1 和 Pod2 在同一台 Node 主机,由 docker0 网桥直接转发请求到 Pod2 上面,- 不经过 Flannel 的转发。

  • Pod1 和 Pod2 不在同一台 Node 主机,Pod 的地址是与 docker0 在同一个网段的,但 docker0 网络与宿主机网卡是两个完全不同的 IP 网段,并且不同的 Node 之间的通讯只能通过宿主机的物理网卡进行。将 Pod 的 IP 地址和所在 Node 的 IP 地址关联起来,通过这个关联让 Pod 可以互相访问。

  • Pod 至 Service 的网络

  • 目前基于性能考虑,全部为 iptables 或 lvs 维护和转发。

  • Pod 到外网

  • Pod 想外网发送请求,查找路由表,转发数据包到宿主机的网卡,宿主机网卡完成路由选择之后,iptables 或 lvs 执行 Masquerade,把源 IP 地址更改为宿主机的网卡的 IP 地址,然后向外网服务器发送请求。

  • 外网访问 Pod

  • 通过 Service 服务来向外部提供 Pod 服务。

ETCD 之于 Flannel 提供说明:

  • 存储管理 Flannel 可分配的 IP 地址段资源

  • 监控 ETCD 中每一个 Pod 的实际 IP 地址,并在内存中建立维护 Pod 节点的路由表

图片

Pod 的多种类型

Pod 存在多种不同的创建类型来满足不一样的用途

图片

ReplicationController

ReplicationController 用来确保容器应用的副本数量始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的 Pod 来代替,而如果异常多出现的容器会自动回收。

ReplicaSet

在新版本(相对而言的较优方式)的 Kubernetes 中建议使用 ReplicaSet 来取代 ReplicationController 来管理 Pod。虽然 ReplicaSet 和 ReplicationController 并没有本质上的不同,只是名字不一样而已,唯一的区别就是 ReplicaSet 支持集合式的 selector,可供标签筛选。

虽然 ReplicaSet 可以独立使用,但一般还是建议使用 Deployment 来自动管理 ReplicaSet 创建的 Pod,这样就无需担心跟其他机制的不兼容问题。比如 ReplicaSet 自身并不支持滚动更新(rolling-update),但是使用 Deployment 来部署就原生支持。

Deployment

Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义方法,用来替代以前使用 ReplicationController 来方便且便捷的管理应用。主要的应用场景,包括:滚动升级和回滚应用、扩容和缩容、暂停和继续。

HPA

HPA 仅仅适用于 Deployment 和 ReplicaSet,在 V1 版本中仅支持根据 Pod 的 CPU 利用率扩缩容,在新版本中,支持根据内存和用户自定义的 metric 动态扩缩容。

StatefulSet

StatefulSet 是为了解决有状态服务的问题,相对于 Deployment 和 ReplicaSet 而已。其主要的使用场景,包括:稳定的持久化存储、稳定的网络标识、有序部署、有序收缩。

DaemonSet

DaemonSet 确保全部或者一些 Node 上面运行一个 Pod 副本。当有 Node 加入集群的时候,也会为它们新加一个 Pod。当有 Node 从集群中移除的时候,这些 Pod 也会被回收。删除 DaemonSet 将会删除它所创建的所有 Pod。

使用 DaemonSet 的典型场景就是,在每个节点运行日志收集、运行监控系统、运行集群存储等服务,只要新加进来的节点都需要运行该服务。

Job

Job 负责批处理任务,仅执行一次的任务,它保证批处理任务的一个或者多个 Pod 成功结束,才会返回成功。

Cront Job

Cront Job 管理是基于时间的 Job,即在给定时间点只运行一次,且周期行的在给定时间点运行特定任务。

作者: Escape
链接: https://www.escapelife.site/p...

image

查看原文

赞 4 收藏 4 评论 0

民工哥 发布了文章 · 4月11日

每天学一个 Linux 命令(108):iptraf

命令简介

ptraf 命令是基于 ncurses 的 IP LAN 监视器,它生成各种网络统计信息,包括 TCP 信息、UDP 计数、ICMP 和 OSPF 信息,以太网负载信息,节点统计信息,IP 校验和错误等。

[root@centos7 ~]# iptraf
-bash: iptraf: command not found
[root@centos7 ~]# yum install iptraf -y

iptraf 命令是一款交互式、色彩鲜艳的 IP 局域网监控工具。它可以显示每个连接以及主机之间传输的数据量。

若在 CentOS Linux 中,其采用的版本是 IPTraf 的衍生版本 iptraf-ng(没有iptrsf这个命令)。

图片

语法格式

iptraf { [ -f ] [ -q ] [ { -i iface | -g | -d iface | -s iface | -z iface | -l iface } [ -t timeout ] [ -B [ -L logfile ] ] ] | [ -h ] }

选项说明

-d  #允许您立即启动指定接口上的详细信息(iface)
-z  #显示指定接口上的数据包计数大小
-i  #立即在指定接口启动IP流量监视器
-u  #允许使用不受支持的接口作为以太网设备
-g  #立即启动常规接口统计

应用举例

先看一个动图展示

图片

图片

立即启动指定接口上的详细信息

[root@centos7 ~]# iptraf-ng -d ens33

图片

查看数据包大小

[root@centos7 ~]# iptraf-ng -z ens33

图片

以上都是用的截图方式展示,其实实际使用过程中都是动态更新的。

每天学一个 Linux 命令(104):zcat

每天学一个 Linux 命令(105):tee

每天学一个 Linux 命令(106):openssl

每天学一个 Linux 命令(107):sar

查看原文

赞 2 收藏 1 评论 0

民工哥 发布了文章 · 4月10日

每天学一个 Linux 命令(106):openssl

命令简介

openssl 命令是强大的安全套接字层密码库。OpenSSL 是一种开源命令行工具,通常用于生成私钥,创建 CSR,安装 SSL / TLS 证书以及标识证书信息。

OpenSSL 运行模式
  • 交互模式

  • 批处理模式

直接输入 openssl 回车进入交互模式,输入带命令选项的 openssl 进入批处理模式。

[root@centos7 ~]# openssl
OpenSSL> version
OpenSSL 1.0.2k-fips  26 Jan 2017

OpenSSL 整个软件包大概可以分成三个主要的功能部分:密码算法库、SSL 协议库以及应用程序。

openssl 命令主要用途
  • 创建和管理私钥,公钥和参数

  • 公钥加密操作

  • 创建 X.509 证书,CSR 和 CRL

  • 消息摘要的计算

  • 使用密码进行加密和解密

  • SSL/TLS 客户端和服务器测试

  • 处理 S/MIME 签名或加密的邮件

  • 时间戳请求,生成和验证

语法格式

openssl command [ command_opts ] [ command_args ]
 
openssl [ list-standard-commands | list-message-digest-commands | list-cipher-commands | list-cipher-algorithms | list-message-digest-algorithms | list-public-key-algorithms]
 
openssl no-XXX [ arbitrary options ]

选项说明

图片读者可自行参考帮助文档 https://www.digicert.com/kb/s...

应用举例

版本信息

[root@centos7 ~]# openssl version
OpenSSL 1.0.2k-fips  26 Jan 2017
[root@centos7 ~]# openssl version -a
OpenSSL 1.0.2k-fips  26 Jan 2017
built on: reproducible build, date unspecified
platform: linux-x86_64
options:  bn(64,64) md2(int) rc4(16x,int) des(idx,cisc,16,int) idea(int) blowfish(idx) 
compiler: gcc -I. -I.. -I../include  -fPIC -DOPENSSL_PIC -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DKRB5_MIT -m64 -DL_ENDIAN -Wall -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches   -m64 -mtune=generic -Wa,--noexecstack -DPURIFY -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DRC4_ASM -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM -DECP_NISTZ256_ASM
OPENSSLDIR: "/etc/pki/tls"
engines:  rdrand dynamic 
#版本号和版本发布日期(OpenSSL 1.0.2k,2017年1月26日)
#使用库构建的选项(options)
#存储证书和私钥的目录(OPENSSLDIR)

生成密码功能

[root@centos7 ~]# openssl rand -base64 15
DYmkj+RY9QUcb4m5aoNV
[root@centos7 ~]# openssl rand -base64 10
RpyTN5W7BLznjA==
[root@centos7 ~]# openssl rand -base64 5
AeQaaBE=

消息摘要算法应用

#用SHA1算法计算文件openssl1.txt的哈西值
[root@centos7 ~]# openssl dgst -sha1 openssl1.txt
openssl1.txt: No such file or directory
[root@centos7 ~]# touch openssl1.txt
[root@centos7 ~]# openssl dgst -sha1 openssl1.txt
SHA1(openssl1.txt)= da39a3ee5e6b4b0d3255bfef95601890afd80709
#用SHA1算法计算文件openssl1.txt的哈西值,输出到文件sha1.txt
[root@centos7 ~]# openssl sha1 -out sha1.txt openssl1.txt
[root@centos7 ~]# cat sha1.txt
SHA1(openssl1.txt)= da39a3ee5e6b4b0d3255bfef95601890afd80709

对称加密应用

#给文件openssl1.txt用base64编码,输出到文件jiami.txt
[root@centos7 ~]# cat openssl1.txt 
openssl
[root@centos7 ~]# openssl base64 -in openssl1.txt -out jiami.txt
[root@centos7 ~]# cat jiami.txt 
b3BlbnNzbAo=

DSA 应用

#生成1024位DSA参数集,并输出到文件jm.pem
[root@centos7 ~]# openssl dsaparam -out jm.pem 1024
Generating DSA parameters, 1024 bit long prime
This could take some time
........+...........+..................+.....+..............+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*
.+...+..........+......+.....+..+......+.........+.........+.................+............+...........+..................+...........+........+............+....+.+......+....+...............................+.................+.................+.+......+.......+..........+........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*
[root@centos7 ~]# cat jm.pem 
-----BEGIN DSA PARAMETERS-----
MIIBHgKBgQCR+2rHHnotQERnaw1i3PaeeGyhZHP7Mjih9RAnNRv3oe+HO2AgiLgr
vWLbT/oRNZhdnvuW8u8b1dmm9xPwwAfkNt0cPyH+28HNJ6ImoO9qQCBVlgPnwmah
WPtA9TXIw7kJVOCUImKKXkbQvKOvlXsTgFHhhQ9GAt9gbHxmWVhqjwIVANzDXsuC
hXZDNAR6O0Dke4p/4H1XAoGAHzT3cByKaD0IN0zCXA0yXMNlyDtE8w7dlv37LcaR
7u0ZV1r4zof/g7Pf+GCHbkVUVPzTrrlkn1Wfqtl2QsmT73jMBwPl+z3Oj7DyFb8J
Nm66epCO1uLaXoIubTZa4QFCuuTarWouizo4qDYQg/vYRDBQK8N5nIh8Wfnte9gq
zTY=
-----END DSA PARAMETERS-----

RSA 应用

#产生1024位RSA私匙,用3DES加密它,口令为mingongge,输出到文件rsa.pem
[root@centos7 ~]# openssl genrsa -out rsa.pem -passout pass:mingongge -des3 1024
Generating RSA private key, 1024 bit long modulus
....................++++++
...............++++++
e is 65537 (0x10001)
[root@centos7 ~]# cat rsa.pem 
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,34B51F9BE30A3448
uvI8+9g2NGBS+t6VoxUW9JvjiSSnXAHVgJXFsiPtQRIQq3tUEv48QVXOXrLMSTei
DOmScLCrU0X+il+Kl2HtTEqmqzxmP+HlbiahSMthTbXUEcqSnKt/80UxzsKFWsag
lYj5yl+skQoMYLHt0JSc2MlWA6tAHPdEb4/BoEN0zerhgVcXDlLeFXm7ni1tUmVj
mbHmM1TV03kxxzd8KQhFsQkwT/aDtm143rxVrD3NpSS4eXbzm8D4B2A3L0DMaUzk
cAql+iggvH4vS3BCKOX6h5Zr9Vyo4CGjvYSyvkASbc+fVKgvmPM9KP0+hedUH2Hc
55K1ND5S0TWa2qFWk511tKbpBT9RM5P7ipcnr3tyya/RSpVZT7EpEUm+EokOrvHg
SY6AgPSojYdDL3/WrQvJAkMQmuckpEW1lNYGSgFsQmRN8gFb8LXhr+uUf8psT3D9
+Cvo5ynkocW1P1sHpJHuA7WtW7SaRbBGwEoPKjzAfKaV41oz9Sknn1PE5LXpvtIA
zn/vVbKVQvD3ho2I2RuX5vtI7Jvy/TeKDOO9fAuNKqlR7/MmqE7OiKZovuh2xHRk
3d3qif8uH6dCe7l6rElqgONNkYYJ/dBgJ+ZV15ahJFNK10JoBqFgF9dj+vFumWGt
7FuN2kk7Qe1YSn13ZZ7M10EWDPxaMXSnjynazC8MLnokRwf1SwqsZW250J9/dbvt
BEE00IQWC+RmaRgJV+H+3gvCHyMZBRGaxUKiOftrM9Ir3w28wk2jwgSm6v6p/WUg
4JUMPAqjft82lv+MwfKn4OHnuIyfgrZGB6+oR52BToQ=
-----END RSA PRIVATE KEY-----

每天学一个 Linux 命令(103):dstat

每天学一个 Linux 命令(104):zcat

每天学一个 Linux 命令(105):tee

查看原文

赞 2 收藏 2 评论 0

民工哥 发布了文章 · 4月9日

每天学一个 Linux 命令(104):zcat

命令简介

zcat 命令用于显示压缩包中文件的内容,可以使用 gzip -d 或 gunzip 或 zcat 将压缩文件恢复为原始格式。zcat 与 gunzip -c 相同。

zcat 命令用于不真正解压缩文件,就能显示压缩包中文件的内容的场合。

语法格式

zcat [ -fhLV ] [ name ...  ]

选项说明

-S  #指定gzip格式的压缩包的后缀
-c  #将文件内容写到标注输出
-d  #执行解压缩操作
-l  #显示压缩包中文件的列表
-L  #显示软件许可信息
-q  #禁用警告信息
-r  #在目录上执行递归操作
-t  #测试压缩文件的完整性
-V  #显示指令的版本信息
-l  #更快的压缩速度
-9  #更高的压缩比

应用举例

打印压缩的内容,将内容传给more命令进行分页显示

[root@centos7 ~]# zcat httpd-2.4.46.tar.gz | more

图片

查看压缩属性信息

[root@centos7 ~]# zcat -l httpd-2.4.46.tar.gz
         compressed        uncompressed  ratio uncompressed_name
            9363314            42301440  77.9% httpd-2.4.46.tar
compressed          #压缩大小 
uncompressed        #未压缩大小
ratio               #压缩比率
uncompressed_name    #未压缩文件的名称

查看普通文件(类似于cat功能)

[root@centos7 ~]# zcat -f test.txt
This is a test line
This is a test line
This is a test line
This is also a test line
This is also a test line
This is also also a test line

其它实例

#测试压缩包的完整性
[root@centos7 ~]# zcat -t httpd-2.4.46.tar.gz
#显示软件许可信息
[root@centos7 ~]# zcat -L httpd-2.4.46.tar.gz
gzip 1.5
Copyright (C) 2007, 2010, 2011 Free Software Foundation, Inc.
Copyright (C) 1993 Jean-loup Gailly.
This is free software.  You may redistribute copies of it under the terms of
the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.
There is NO WARRANTY, to the extent permitted by law.

每天学一个 Linux 命令(101):pstree

每天学一个 Linux 命令(102):tac

每天学一个 Linux 命令(103):dstat

查看原文

赞 2 收藏 2 评论 0