分类 DevOps 下的文章

端口映射

docker create -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 --name hello-mysql mysql:5.7

-p HostPort:ContainerPort | IP:HostPort:ContainerPort | HostPort:ContainerPort

  • 查看端口映射

    • docker port hello-mysql

容器互联

--link name:alias,name连接容器的名称,alias连接的别名

场景:我们无需暴露mysql的情况下,让web应用使用mysql;

docker run -d -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
docker run -d --link mysql01:mysql --name tomcat tomcat:7

docker exec -it tomcat bash
cat /etc/hosts

使用Docker过程中,往往需要对数据进行持久化,或者多个容器之间进行数据共享,这就需要我们熟悉容器的数据管理操作

容器中管理数据主要的两种方式:

  • 数据卷(Data Volumes):容器内数据直接映射到本地主机环境
  • 数据卷容器(Data Volumes Containers):使用特定容器维护数据

数据卷

将主机操作系统目录直接映射进容器,类似于Linux中的mount。数据卷很好的解耦了容器应用和数据。对数据卷内数据的操作(无论是在本地主机还是容器内),都会立即生效。

docker run -d -p 3307:3306 -v /my/custom:/etc/mysql/conf.d \
-v /my/own/datadir:/var/lib/mysql --restart always --name mysql01 mysql:5.7

-v hostDir:containerDir:hostDir不存在会自动创建,默认权限是rw,也可以改为ro,这样容器内部就无法对数据卷的数据进行修改了。

docker run -d -p 3307:3306 -v /my/custom:/etc/mysql/conf.d:ro \
-v /my/own/datadir:/var/lib/mysql --restart always --name mysql01 mysql:5.7
#数据卷创建
docker volume create [OPTIONS] [VOLUME]
docker volume create hello
docker run -d -p 3307:3306 -v hello:/etc/mysql/conf.d \
-v /my/own/datadir:/var/lib/mysql --restart always --name mysql01 mysql:5.7

#数据卷列表
docker volume ls

#数据卷详情
docker volume inspect hello
[
    {
        "CreatedAt": "2020-04-08T06:43:08Z",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/hello/_data",
        "Name": "hello",
        "Options": {},
        "Scope": "local"
    }
]
#docker cp 用于容器与主机之间的数据拷贝
docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
  • SRC_PATH 指定为一个文件

    • DEST_PATH 不存在:文件名为 DEST_PATH,内容为SRC的内容
    • DEST_PATH 不存在并且以 / 结尾:报错
    • DEST_PATH 存在并且是文件:目标文件内容被替换为SRC_PATH的文件内容。
    • DEST_PATH 存在并且是目录:文件复制到目录内,文件名为SRC_PATH指定的名字
  • SRC_PATH 指定为一个目录

    • DEST_PATH 不存在:DEST_PATH创建文件夹,复制源文件夹内的所有内容
    • DEST_PATH 存在是文件:报错
    • DEST_PATH 存在是目录

      • SRC_PATH 不以 /. 结束:源文件夹复制到目标里面
      • SRC_PATH/. 结束:源文件夹里面的内容复制到目标里面

      自动创建文件夹不会做递归。把父文件夹做好

数据卷容器

如果需要在多个容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。数据卷容器也是一个容器,但他专门用来提供数据卷供其他容器挂载。

docker run -it -v /idata --name idata ubuntu

docker run -it --volumes-from idata --name d01 ubuntu
docker run -it --volumes-from idata --name d02 ubuntu
#使用--volumes-from参数所挂载的数据卷容器本身不需要保持在运行状态

数据卷的用法细节

docker run -d -P --name nginx nginx
#方便修改nginx的配置和html页面等
#容器中 /usr/share/nginx/html
#容器中 /etc/nginx

##参照一下各种写法
# hostPath:containerPath
docker run -d -P --name nginx -v /opt/nginx/html:/usr/share/nginx/html nginx;
    #为什么看到的是403而不是index页面内容。原来容器里面变为空了?主机的内容复制到容器中,导致,容器同步到了主机的空文件夹。
    #特别是配置问津,必须提前保证我们主机挂载的目录里面提前有内容。
docker run -d -P --name nginx -v /opt/nginx:/etc/nginx nginx
    #为什么docker ps看不到;出错了。open() "/etc/nginx/nginx.conf" failed (2: No such file or directory) nginx: [emerg] open() "/etc/nginx/nginx.conf" failed (2: No such file or directory)
#我就想自定义挂载路径,并且把他们挂载出来?
    # 1、复制容器的文件
        docker cp
        1、启动一个nginx,先不挂载。
        2、docker cp把运行中的nginx的内容复制出来
            Usage:    docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
                    docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
        docker cp nginx:/usr/share/nginx/html /opt/hahanginx
        nginx:/usr/share/nginx/html/. 把html里面的内容复制到 /opt/hahanginx
        nginx:/usr/share/nginx/html 把html文件夹复制到 /opt/hahanginx
        
        
        完整过程
        mkdir /opt/nginx
        docker cp nginx:/usr/share/nginx/html /opt/nginx 复制html
        docker cp nginx:/etc/nginx/. /opt/nginx/conf
        docker run -d -P --name nginx -v /opt/nginx/conf:/etc/nginx -v /opt/nginx/html:/usr/share/nginx/html nginx
        
# 匿名卷方式volume,挂载任意目录
docker run -d -P --name nginx02 -v 容器路径
eg:
docker run -d -P --name nginx02 -v /usr/share/nginx/html -v /etc/nginx nginx
想要知道到底迎合到主机的哪里了?
docker inspect nginx02.
"Mounts": [
            {
                "Type": "volume",
                "Name": "9f4f8ac4c9cd9cb77df7a5386a5b68520c98ea1bb28e26b6593255c1d0ff9cdf",
                "Source": "/var/lib/docker/volumes/9f4f8ac4c9cd9cb77df7a5386a5b68520c98ea1bb28e26b6593255c1d0ff9cdf/_data",
                "Destination": "/usr/share/nginx/html",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            },
            {
                "Type": "volume",
                "Name": "68afef2bf4979e2c9369f6eb68f8a94adc61e63d3a1fb3dad7469e243442cf32",
                "Source": "/var/lib/docker/volumes/68afef2bf4979e2c9369f6eb68f8a94adc61e63d3a1fb3dad7469e243442cf32/_data",
                "Destination": "/etc/nginx",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ],

#匿名挂载的缺点?不好维护。 docker volume可以维护他们
docker volume ls

#具名挂载。有卷。如果有可视化界面。我们就知道卷是干嘛,就不乱删除了。
#创建好的卷,会自动的和容器中需要挂载的这个文件夹做好同步。
docker volume create 卷名字, 创建一个卷。/var/lib/docker/volumes/自定义的卷名/_data
docker run -d -P --name nginx03 -v nginxconf:/etc/nginx -v nginxhtml:/usr/share/nginx/html nginx
最佳实战。

怎么判断挂载的是卷名而不是本机目录名
  不以/开始就是卷名,以/开始就是主机名。 
 
#改变文件的读写权限
#ro:readonly rw:readwrite; 指定容器对我们这个挂载出来的内容的读写权限
docker run -d -P --name nginx04 -v nginx04conf:/etc/nginx:ro -v nginx04html:/usr/share/nginx/html:rw nginx
ro:效果
root@c721b01b2752:/etc/nginx# echo 123 > nginx.conf
bash: nginx.conf: Read-only file system
容器内不能再对ro指定的所有进行修改了。

我们以使用Docker的方式安装MySQL为例,快速体会Docker的基本操作

镜像操作

下载镜像 docker pull mysql

#我们应该先去Docker Hub寻找我们感兴趣的镜像
docker pull image_name[:Tag]
#1、tag一般为镜像的版本,不指定默认下载latest版本
#2、默认镜像是从Docker Hub下载,国内比较慢,推荐使用自己的阿里云加速
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://82m9ar63.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

l8u4jp1z.png

  • 以上下载过程看出,镜像是分层的(Layer)。c499e6d256d6是当前层的唯一id(完整的id为256bit,64个十六进制字符组成)。
  • 不同的镜像如果有相同的层,本地只会存储一份,减小了存储空间
  • 严格说,下载镜像需要制定指定仓库名称,不过从Docker Hub下载的可以忽略前缀。如

    • docker pull docker.io/library/mysql:5.7

列出镜像 docker images

docker images

l8u4k2c4.png

  • REPOSITORY:来源于哪个仓库
  • TAG:镜像版本标签信息
  • IMAGE ID :镜像唯一id
  • CREATED:镜像最后更新时间
  • SIZE:镜像大小

查看详情 docker inspect

docker inspect image_name[:tag]
docker inspect image_id  

删除镜像 docker rmi

docker rmi image_name[:tag] 或者 docker rmi image_id

理解镜像

1、疑问一:

Docker每一个容器都是一个完整的这个应用的运行环境。所有应用最起码的基本环境是linux

SB微服务做成镜像。基本环境就是java环境,

如果我下载了100个镜像,启动了100个容器。100个linux在运行?

UFS:特点;git。增量记录文件改变。分层系统。需要经常读写变化的,只在变化层。

容器操作

启动容器

#docker run [OPTIONS] IMAGE [COMMAND] [ARG...] 常用选项
-d  守护态运行
-p  Publish a container's port(s) to the host ( container和host端口映射)
-i  以交互模式运行容器,通常与 -t 同时使用
-t  为容器重新分配一个伪输入终端,通常与 -i 同时使用
--name="nginx-lb"  为容器指定一个名称
-v, --volume value  Bind mount a volume (default [])
docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 --name hello-mysql mysql:5.7

#查看所有运行中的容器
docker ps 
#查看所有容器
docker ps -a
#docker create 和 docker run的区别
docker create -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 --name hello-mysql mysql:5.7
#create新建容器,run新建并启动。create相当于 run -d设置

进入容器

#docker exec  [OPTIONS] CONTAINER COMMAND [ARG...]
#Run a command in a running container
docker exec -it hello-mysql /bin/bash    
#尝试连接MySQL
mysql -uroot -p123456
#扩展
docker exec -d hello-mysql touch /hello.txt
docker exec -it hello-mysql mysql -uroot -p

#删除
docker rm container_id/container_name
#查看运行日志
docker logs container_id/container_name

其他命令

Docker 命令手册

可视化

  • Portainer(先用这个)
docker run -d -p 8088:9000 \
--restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer
  • Rancher(CI/CD再用这个)
#安装rancher-server
docker run --name rancher-server -p 8000:8080 -v /etc/localtime:/etc/localtime:ro  -d  rancher/server
#安装agent
docker run --rm --privileged -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/rancher:/var/lib/rancher rancher/agent:v1.2.11 http://39.101.191.131:8000/v1/scripts/D3DBD43F263109BB881F:1577750400000:7M0yBzCw4XSxJklD7TpysYIpI

为什么是Docker?

l8u4gvqk.png

Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。

Docker解决了什么问题

  • 快速交付和部署(镜像与容器)
  • 资源的高效利用和隔离(高密度部署)
  • 轻松的迁移和扩展(一次封装,到处运行)

l8u4hhsd.png

Docker使用步骤

  • 安装Docker(安装应用商店)
  • 寻找/下载镜像(寻找/下载app)
  • 启动容器(启动应用)
  • 移植(别的手机安装应用商店,继续以前流程)

容器化对比虚拟机

对比属性ContainerVM
隔离性基于进程隔离提供资源的完全隔离
启动时间秒级分钟级
内核共用宿主机内核使用独立内核
占用资源MB级GB级
系统支持容量单机支持上千个容器一般几十个

核心概念

l8u4irdr.png

Docker 镜像

Docker镜像类似于虚拟机镜像,可以将他理解为一个只读的模板。

Docker 容器

Docker容器类似于一个轻量级的沙箱,Docker利用容器来运行和隔离应用。容器是从镜像创建来的。容器可以启动、停止、删除,容器之间彼此隔离,互不可见。

可以把容器看做是一个简易版的Linux系统环境(包括root用户权限、进程空间、用户空间和网络空间等)以及运行在其中的应用程序打包而成的盒子

Docker 仓库

Docker仓库是存储镜像的仓库。可以有Public(公有仓库)和Private(私有仓库)。最大的公有仓库是Docker Hub

Docker面向对象
镜像
容器对象

安装启动

阿里云安装

yum install docker
systemctl enable docker
systemctl start docker

docker -v
docker info

标准方式安装

#移除旧版本
yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
#安装Docker其他依赖
yum install -y yum-utils \
  device-mapper-persistent-data \
  lvm2
#设置Docker yum源
yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
#安装Docker CE
yum install -y docker-ce docker-ce-cli containerd.io

#安装指定版本的Docker
yum list docker-ce --showduplicates | sort -r
yum install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io
#启动Docker
systemctl enable docker
systemctl start docker

课程地址:18个Linux Shell脚本经典案例【共20课时】_自动化运维课程-51CTO学堂

服务器系统配置初始化

当我们拿到一台崭新的服务器时候需要对其进行初始化,一般的步骤如下:

  1. 安装系统新能分析工具已经其他的工具
  2. 设置时区并同步时间
  3. 禁用selinux
  4. 清空防火墙默认策源
  5. 历史命令显示操作时间
  6. 禁止root远程登录
  7. 禁止定时任务发送邮件
  8. 设置最大打开文件数
  9. 减少Swap使用
  10. 系统内核参数的优化

当我们的服务器只有一台的时候其实还好,但如果是 10 台,100 台呢?我们不可能还是手动的去一台一台的设置,我们肯定要借助脚本来自动完成。

#/bin/bash
# 安装系统性能分析工具及其他
yum install gcc make autoconf vim sysstat net-tools iostat iftop iotp wget lrzsz lsof unzip openssh-clients net-tool vim ntpdate -y

# 设置时区并同步时间
ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
if ! crontab -l |grep ntpdate &>/dev/null ; then
    (echo "* 1 * * * ntpdate time.windows.com >/dev/null 2>&1";crontab -l) |crontab 
fi

# 禁用selinux
sed -i '/SELINUX/{s/permissive/disabled/}' /etc/selinux/config

# 关闭防火墙
if egrep "7.[0-9]" /etc/redhat-release &>/dev/null; then
    systemctl stop firewalld
    systemctl disable firewalld
elif egrep "6.[0-9]" /etc/redhat-release &>/dev/null; then
    service iptables stop
    chkconfig iptables off
fi

# 历史命令显示操作时间
if ! grep HISTTIMEFORMAT /etc/bashrc; then
    echo 'export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S  `whoami` "' >> /etc/bashrc
fi

# SSH超时时间
if ! grep "TMOUT=600" /etc/profile &>/dev/null; then
    echo "export TMOUT=600" >> /etc/profile
fi

# 禁止root远程登录 切记给系统添加普通用户,给su到root的权限
sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config

# 禁止定时任务向发送邮件
sed -i 's/^MAILTO=root/MAILTO=""/' /etc/crontab 

# 设置最大打开文件数
if ! grep "* soft nofile 65535" /etc/security/limits.conf &>/dev/null; then
cat >> /etc/security/limits.conf << EOF
    * soft nofile 65535
    * hard nofile 65535
EOF
fi

# 系统内核优化
cat >> /etc/sysctl.conf << EOF
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_tw_buckets = 20480
net.ipv4.tcp_max_syn_backlog = 20480
net.core.netdev_max_backlog = 262144
net.ipv4.tcp_fin_timeout = 20  
EOF

# 减少SWAP使用
echo "0" > /proc/sys/vm/swappiness

发送告警邮件

安装软件

yum install mailx -y

进入qq邮箱首页,点击设置>账户,然后找到下图截取的地方(需要设置的,如图)

设置完之后呢,就要把生成的授权码作为邮箱的password的啦~

配置/etc/mail.rc文件【下面的配置qq是假的,别用】

#设置发件人名称
set [email protected]
#设置邮件服务器
set smtp=smtp.qq.com
#填写自己邮箱地址
set [email protected]
#输入邮箱验证码
set smtp-auth-password=pfljngafoqaxecff
#smtp的认证方式,默认是login
set smtp-auth=login

测试【已经完成】

 echo "admin ,文件内容" | mail -s "标题" 你的[email protected]

一键查看服务器利用率

#!/bin/bash
function cpu(){
    
    util=$(vmstat | awk '{if(NR==3)print $13+$14}')
    iowait=$(vmstat | awk '{if(NR==3)print $16}')
    echo "CPU -使用率:${util}% ,等待磁盘IO相应使用率:${iowait}:${iowait}%"
 
}
function memory (){
 
    total=`free -m |awk '{if(NR==2)printf "%.1f",$2/1024}'`
    used=`free -m |awk '{if(NR==2) printf "%.1f",($2-$NF)/1024}'`
    available=`free -m |awk '{if(NR==2) printf "%.1f",$NF/1024}'`
    echo "内存 - 总大小: ${total}G , 使用: ${used}G , 剩余: ${available}G"
}
disk(){
    
    fs=$(df -h |awk '/^\/dev/{print $1}')
    for p in $fs; do
        mounted=$(df -h |awk '$1=="'$p'"{print $NF}')
        size=$(df -h |awk '$1=="'$p'"{print $2}')
        used=$(df -h |awk '$1=="'$p'"{print $3}')
        used_percent=$(df -h |awk '$1=="'$p'"{print $5}')
        echo "硬盘 - 挂载点: $mounted , 总大小: $size , 使用: $used , 使用率: $used_percent"
    done
 
}
function tcp_status() {
    summary=$(ss -antp |awk '{status[$1]++}END{for(i in status) printf i":"status[i]" "}')
    echo "TCP连接状态 - $summary"
}
cpu
memory
disk
tcp_status