0%

vim

三种模式:

  • 命令模式 或 普通模式
  • 插入模式 或 编辑模式
  • 扩展命令模式 或 命令行模式 或 末行模式

命令模式

光标跳转

字符间跳转
  • j 下
  • k 上
  • h 左
  • l 右
单词间跳转
  • w 定位下一个单词
当前页跳转
  • H 定位页首
  • M 定位中间行
  • L 定位页末
  • zt 滚动屏幕, 使当前行置顶 top
  • zz 滚动屏幕, 使当前行置中
  • zb 滚动屏幕, 使当前行置底 bottom
行首行尾跳转
  • ^ 定位行首第一个非空字符
  • 0 定位行尾
  • $ 定位行首
行间移动
  • gg 定位文首
  • G 定位文末
  • #G 定位指定行行首, 例如定位第5行: `5G`
句间和段落间移动
  • ) 下一句
  • ( 上一句
  • } 下一段
  • { 上一段
翻屏操作
  • ctrl+f 向后翻一屏
  • ctrl+d 向后翻半屏
  • ctrl+b 向前翻一屏
  • ctrl+u 向前翻半屏

字符编辑

  • x 剪切光标处字符
  • p 黏贴
  • ~ 转换大小写, 然后光标向后移一位
  • J 删除当前行前后的换行符

替换 replace

  • r 替换光标所在处的一个字符, 按下r,然后再按替换后的字符
  • R 切换成REPLACE模式, ESC回到命令模式, 按下r, 然后再输入替换后的内容

删除 delete

  • d 删除, 可结合光标跳转, 实现范围删除
  • d$ 删除到行尾
  • d0 删除到行首
  • d^ 删除到非空行首
  • dd 删除当前行
  • #dd 删除多行, 从当前行开始, 删除#行
  • D 删除到行尾, 等同于d$

复制 yank

  • y 复制, 行为相似于d命令
  • Y 复制整行

粘贴 paste

  • p 整行, 则粘贴到下一行, 否则粘贴到光标后
  • P 整行, 则粘贴到上一行, 否则粘贴到光标后

命令模式 切换到 插入模式

以下快捷键, 进入插入模式

  • i 不动
  • I 定位行首
  • a 向后移一位
  • A 定位行尾
  • o 定位下一行行首, 并开辟新行
  • O 定位上一行行首, 并开辟新行

插入模式

从光标前输入数据

末行模式

  • :wq 存盘并退出
  • :q! 不存盘强制退出
  • :r file 将file中的内容写入到当前文件, 例如`:r a.log`就把a.log中的内容写入到当前文件
  • :w file 将当前文件内容写入file文件, 如果file已存在, 需要`:w! file`强制覆盖文件
  • :!command 不退出文件,执行命令
  • :r!command 将执行命令的输出写入到当前文件
  • 地址定界
1
2
3
4
5
6
7
8
9
10
11
# 		第几行, 例如2表示第2行
#,# 第#行到到第#行, 例如 2,5 表示2到5行
#,+# 第#行加#行, 例如 2,+3 表示2到5行
. 当前行
$ 最后一行, .,$-1 表示当前行到倒数第二行
% 全文, 相当于1、$

/pattern/ 从当前行开始,直到第一次匹配到的行
/pattern1/,/pattern2/ 从pattern1第一次匹配到行, 到pattern2第一次匹配到的行
#,/pattern/ 从指定行开始, 到第一次pattern匹配到行
/pattern/,$ 从pattern第一次匹配到的行, 到最后一行

地址定界后跟一个编辑命令

1
2
3
4
d 		删除
y 复制
w file 将范围内的行另存到file文件中
r file 在指定位置插入file文件中的所有内容
  • 查找并替换
1
2
3
4
5
6
7
8
s/要查找的内容/替换为的内容/修饰符

# 要查找的内容:可使用正则
# 替换为的内容:不能使用正则,但可以使用\1, \2, ...等后向引用符号;还可以使用“&”引用前面查找时查找到的整个内容
# 修饰符
# i 忽略大小写
# g 全局替换
# gc 全局替换, 每次替换前询问
  • u 撤销, 相当于windows中的ctrl+z
  • #u 撤销多步
  • U 撤销此行的所有操作
  • ctrl+r 取消撤销, 相当于windows中的ctrl+y

高级用法

范例: 粘贴”wang”100次

1
100iwang [ESC]

di” 光标在” “之间,则删除” “之间的内容
yi( 光标在()之间,则复制()之间的内容
vi[ 光标在[]之间,则选中[]之间的内容
dtx 删除字符直到遇见光标之后的第一个 x 字符
ytx 复制字符直到遇见光标之后的第一个 x 字符

定制vim的工作特性

配置文件:

  • /etc/vimrc 全局
  • /.vimrc 个人

可视化模式

如何进入可视化模式

  • v 面向字符
  • V 面向整行
  • ctrl + v 面向块(列)

选中的文字可以被删除、复制、变更、过滤、搜索、替换等

范例: 在文件每一行行首插入#, 然后再删除

1
2
3
4
5
6
7
8
9
10
1. gg
2. ctrl + v
3. G
4. I
5. 输入#
6. ESC退出 插入#成功

7. ctrl + v
8. d 删除成功
9 ESC退出

vim总结



cat

  • -n 对输出内容标行号
  • -b 对输出内容非空行标行号
  • -E 显示行结束符$
  • -A 显示所有控制符
  • -s 压缩连续的空行成一行

nl

相当于 cat -b

tac

cat倒着写tac, 功能也是恰如其名: 逆向显示文本内容

rev

将每行的内容逆向显示

  • -c 指定前几个字符
  • -n 指定前几行
    当n是负数(-#),表示舍弃最后#行

tail

  • -f –follow
  • -c 指定后几个字符
  • -n 指定后几行
    当n是显示整数(+#),表示从第#行开始到结束

分页查看文件内容 less 和 more

一般搭配管道符使用,less和more差不多,区别在于more只能向下翻页

查看非文本内容

hexdump、od、xxd

最常的是hexdump,常用选项 -C

cut

提取文本文件或STDIN数据的指定列

1
cut [OPTION]... [FILE]...
  • -d delimiter 指明分隔符
  • -f fileds
    • # 第#个字段, 例如: 3
    • #,#[,#] 离散的多个字段, 例如: 1,3,6
    • #-# 连续的多个字段, 例如: 1-6
    • 混合使用: 1-3,7
  • -c 按字符切割
  • –output-delimiter 指定输出分隔符
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
[19:22:09 root@centos7 data]#cut -d : -f1-3 --output-delimiter=. passwd   
root.x.0
bin.x.1
daemon.x.2
adm.x.3
lp.x.4
sync.x.5
shutdown.x.6
halt.x.7
mail.x.8
operator.x.11
games.x.12
ftp.x.14
nobody.x.99
systemd-network.x.192
dbus.x.81
polkitd.x.999
sshd.x.74
postfix.x.89
lujinkai.x.1000
test.x.1001
test2.x.1002
gentoo.x.1003
tomcat.x.1004
mysql.x.1005
[14:49:02 root@centos7 data]#cut -c1-3 passwd
roo
bin
dae
adm
lp:
syn
shu
hal
mai
ope
gam
ftp
nob
sys
dbu
pol
ssh
pos
luj
tes
tes
gen
tom
mys

合并多个文件 paste

合并多个文件同行号的列到一行

1
paste [OPTION]... [FILE]...
  • -d 分隔符, 指定分隔符, 默认分隔符TAB
  • -s 所有行合成一行显示

文本统计 wc

用于统计文件或STDIN的行总数、单词总数、字节总数和字符总数

  • -l –lines 统计行数
  • -w –words 统计单词数 (规则是有空格或者换行分隔才是单词)
  • -m –chars 打印字符数 (空格和换行和tab都是字符)
  • -L –max-line-length 统计文件中最长行的长度

整理文本 sort

字典排序, 从小到大

  • -r 反方向
  • -R 随机排序
  • -n 自然排序
  • -h 人类可读排序, 如: 2k 1G
  • -f 忽略大小写
  • -u 合并重复项, 即去重
  • -t 指定字段界定符
  • -k 配合-t使用, 指定使用第几个字符来排序

范例: 按照UID进行排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[21:18:38 root@centos7 data]#cat /etc/passwd | sort -n -t: -k 3    
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
lujinkai:x:1000:1000:lujinkai:/home/lujinkai:/bin/bash
test:x:1001:1001::/home/test:/bin/bash
test2:x:1002:1002::/home/test2:/bin/bash
gentoo:x:1003:1003:Gentoo Distribution:/home/gentoo:/bin/csh
tomcat:x:1004:1006::/home/tomcat:/sbin/nologin
mysql:x:1005:1009::/home/mysql:/bin/bash

去重 uniq

从输入中删除前后相接的重复的行

1
uniq [OPTION]... [FILE]...
  • -c 显示每行重复出现的次数, 重复的行必须相邻, 否则会单独统计
  • -d 仅显示重复的行
  • -u 仅显示不重复的行

uniq常和sort命令一起配合使用

1
sort userlist.txt | uniq -c	

比较文本 diff和path

diff

diff命令比较两个文件之间的区别

常用选项 -u

patch

复制在其他文件中进行的改变 (要谨慎使用)

1
2
diff -u foo.conf foo2.conf > foo.patch
patch -b foo.conf foo.patch

比较二进制文件 cmp

查看二进制文件的不同

练习

1、找出ifconfig “网卡名” 命令结果中本机的IPv4地址

1
2
3
4
5
6
7
8
9
10
11
[root@47105171233 wwwlogs]# cut -d' ' -f1 lujinkai.cn_nginx.log | sort -t' ' -k1 | uniq -c | sort -nr | head -n10       
276 112.64.64.36
186 183.136.190.62
184 112.64.64.47
184 112.64.64.40
184 112.64.64.33
121 176.9.32.203
94 47.92.207.41
92 112.64.64.43
92 112.64.64.39
92 112.64.64.35

2、查出分区空间使用率的最大百分比值
3、查出用户UID最大值的用户名、UID及shell类型
4、查出/tmp的权限,以数字方式显示
5、统计当前连接本机的每个远程主机IP的连接数,并按从大到小排序

参考:https://kubernetes.io/zh/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/

CNI:Container Network Interface,容器网络接口

kubernetes 的网络插件遵从 CNI 规范的 v0.4.0 版本

网络插件有很多,最常用的是 flannel 和 Project Calico,生产环境用后者的最多

跨主机 pod 之间通信,有两种虚拟网络,有两种:overlay 和 underlay

  • overlay:叠加网络 ,搭建隧道
  • underlay:承载网络,设置路由表

overlay

以 flannel 为例,flannel 默认配置的网段是 10.224.1.0/16,flannel 在每个节点创建一个网卡 flannel.1,这是一个隧道,ip 为 10.2441.0/32 - 10.244.255/32,而每个节点上的容器的 ip 为10.244.x.1/24 - 10.244.x.254/24,也就是说 flannel 默认支持最多 256 个节点,每个节点上又最多支持 256 个容器

underlay

https://github.com/easzlab/kubeasz

角色 ip 主机名 描述
master1 10.0.1.1/21 k8s-master1.ljk.cn 同时部署ansible
master2 10.0.1.2/21 k8s-master2.ljk.cn
node1 10.0.1.3/21 k8s-node1.ljk.cn
node2 10.0.1.4/21 k8s-node2.ljk.cn
etcd1 10.0.2.1/21 k8s-etcd1.ljk.cn
etcd2 10.0.2.2/21 k8s-etcd2.ljk.cn
etcd3 10.0.2.3/21 k8s-etcd3.ljk.cn
HAProxy1 + keepalived 10.0.2.1/21 和etcd1混用
HAProxy2 + keepalived 10.0.2.2/21 和etcd2混用
harbor 10.0.2.3/21 和etcd3混用

架构图:

kubeasz 部署 k8s

https://github.com/easzlab/kubeasz/blob/master/docs/setup/00-planning_and_overall_intro.md

校准时区和同步时间

  • 所有服务器,校准时区

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 显示系统全部的时区
    $ timedatectl list-timezones

    # 查找上海
    $ timedatectl list-timezones | grep 'Shanghai'
    Asia/Shanghai
    # 设置时区为上海
    $ timedatectl set-timezone Asia/Shanghai
    # 查看
    $ timedatectl status
    Local time: Mon 2020-07-27 21:56:19 CST
    Universal time: Mon 2020-07-27 13:56:19 UTC
    RTC time: Mon 2020-07-27 13:56:19
    Time zone: Asia/Shanghai (CST, +0800)
    System clock synchronized: no
    NTP service: inactive
    RTC in local TZ: no
    # 查看当前所在的时区
    $ ll /etc/localtime
    lrwxrwxrwx. 1 root root 35 Jul 23 16:33 /etc/localtime -> ../usr/share/zoneinfo/Asia/Shanghai
  • 确保各节点时区设置一致、时间同步。 如果你的环境没有提供NTP 时间同步,推荐集成安装chrony

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
      [root@k8s-master1 ~]$apt install -y chrony
    [root@k8s-master1 ~]$sed -n '/^#/!p' /etc/chrony/chrony.conf
    server ntp.aliyun.com iburst
    server time1.cloud.tencent.com iburst
    keyfile /etc/chrony/chrony.keys
    driftfile /var/lib/chrony/chrony.drift
    logdir /var/log/chrony
    maxupdateskew 100.0
    rtcsync
    makestep 1 3
    allow 10.0.0.0/16
    allow 10.0.1.0/16
    allow 10.0.2.0/16
    allow 10.0.3.0/16
    allow 10.0.4.0/16
    allow 10.0.5.0/16
    allow 10.0.6.0/16
    allow 10.0.7.0/16
    local stratum 10
    [root@k8s-master1 ~]$systemctl restart chronyd.service

    # 其他节点
    $apt install -y chrony
    $vim /etc/chrony/chrony.conf
    ...
    server 10.0.1.1 iburst # 只修改此行
    ...
    $systemctl restart chronyd.service

python

kubeasz 基于 ansible,而ansible 基于 python 的,所以所有服务器都需要安装 python 环境

1
2
apt update
apt-get install python3 –y

ansible

在 master1 上安装 ansible

1
2
3
4
5
6
7
8
9
10
[root@k8s-master1 ~]$apt-get install git python3-pip -y
# 优化pip
[root@k8s-master1 ~]$vim ~/.pip/pip.conf # 没有就创建
[global]
index-url = https://mirrors.aliyun.com/pypi/simple/

[install]
trusted-host=mirrors.aliyun.com

[root@k8s-master1 ~]$pip3 install ansible # 这一步时间很长,建议更改为阿里的pip源

设置 ssh 免密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function ssh_push_key() {
ips=(
10.0.1.2
10.0.1.3
10.0.1.4
10.0.2.1
10.0.2.2
10.0.2.3
)
[ "$1" ] && ips=($@)
apt install -y sshpass
[ -f ~/.ssh/id_rsa ] || ssh-keygen -t rsa -f ~/.ssh/id_rsa -P '' >/dev/null 2>&1
export SSHPASS=ljkk
for ip in ${ips[@]}; do
(
timeout 5 ssh $ip echo "$ip: SSH has passwordless access!"
if [ $? != 0 ]; then
sshpass -e ssh-copy-id -o StrictHostKeyChecking=no root@$ip >/dev/null 2>&1
timeout 5 ssh $ip echo "$ip: SSH has passwordless access!" || echo "$ip: SSH has no passwordless access!"
fi
) &
done
wait
}
ssh_push_key

keepalived

10.0.2.1/21 和 10.0.2.2/21 均安装 keepalived

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 安装
$apt install keepalived -y
$vim /etc/keepalived/keepalived.conf
global_defs {
router_id keepalived1
vrrp_skip_check_adv_addr
vrrp_garp_interval 0
vrrp_gna_interval 0
vrrp_mcast_group4 224.0.0.18
}

vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 1 # 另一个keepalived设置为2
priority 100 # 另一个keepalived设置为120
advert_int 1
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
10.0.2.188 dev eth0 label eth0:0
}
}
$systemctl restart keepalived.service

haproxy

10.0.2.1/21 和 10.0.2.2/21 均安装 haproxy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# 编译安装lua,过程略...
# 编译安装haproxy
$wget http://www.haproxy.org/download/2.2/src/haproxy-2.2.6.tar.gz
$apt install make gcc build-essential libssl-dev zlib1g-dev libpcre3 libpcre3-dev libsystemd-dev libreadline-dev -y
$useradd -r -s /sbin/nologin -d /var/lib/haproxy haproxy
$mkdir /usr/local/haproxy
$tar zxvf haproxy-2.2.6.tar.gz
$cd haproxy-2.2.6/
$make ARCH=x86_64 TARGET=linux-glibc USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_LUA=1 LUA_INC=/usr/local/lua/src/ LUA_LIB=/usr/local/lua/src/
$make install PREFIX=/usr/local/haproxy
$vim /etc/profile # export PATH=/usr/local/haproxy/sbin:$PATH
$. /etc/profile
$haproxy -v
$haproxy -V
$haproxy -vv

# 配置文件
$mkdir /var/lib/haproxy
$mkdir /etc/haproxy
$vim /etc/haproxy/haproxy.cfg
global
chroot /usr/local/haproxy
stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
user haproxy
group haproxy
daemon
nbproc 1
maxconn 100000
pidfile /var/lib/haproxy/haproxy.pid

defaults
option redispatch
option abortonclose
option http-keep-alive
option forwardfor
maxconn 100000
mode http
timeout connect 120s
timeout server 120s
timeout client 120s
timeout check 5s

listen stats
stats enable
mode http
bind 0.0.0.0:9999
log global
stats uri /haproxy-status
stats auth admin:123456

listen k8s-api-8443
bind 10.0.2.188:6443
mode tcp
server master1 10.0.2.1:8443 check inter 2000 fall 3 rise 5
server master2 10.0.2.2:8443 check inter 2000 fall 3 rise 5

# 启动文件
$mkdir /etc/haproxy/conf.d/
$vim /lib/systemd/system/haproxy.service
[Unit]
Description=HAProxy Load Balancer
After=syslog.target network.target

[Service]
ExecStartPre=/usr/local/haproxy/sbin/haproxy -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/conf.d/ -c -q
ExecStart=/usr/local/haproxy/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/conf.d/ -p /var/lib/haproxy/haproxy.pid
ExecReload=/bin/kill -USR2 $MAINPID

[Install]
WantedBy=multi-user.target

$systemctl start haproxy.service

下载项目源码

1
2
3
4
5
$export release=2.2.4
$curl -C- -fLO --retry 3 https://github.com/easzlab/kubeasz/releases/download/${release}/easzup
$chmod +x ./easzup
# 使用工具脚本下载
$./easzup -D

配置集群参数

1
2
cd /etc/ansible
cp example/hosts.multi-node hosts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# 'etcd' cluster should have odd member(s) (1,3,5,...)
# variable 'NODE_NAME' is the distinct name of a member in 'etcd' cluster
[etcd]
10.0.2.1 NODE_NAME=etcd1
10.0.2.2 NODE_NAME=etcd2
10.0.2.3 NODE_NAME=etcd3

# master node(s)
[kube-master]
10.0.1.1
10.0.1.2

# work node(s)
[kube-node]
10.0.1.3
#10.0.1.4

# [optional] harbor server, a private docker registry
# 'NEW_INSTALL': 'yes' to install a harbor server; 'no' to integrate with existed one
# 'SELF_SIGNED_CERT': 'no' you need put files of certificates named harbor.pem and harbor-key.pem in directory 'down'
[harbor]
#192.168.1.8 HARBOR_DOMAIN="harbor.yourdomain.com" NEW_INSTALL=no SELF_SIGNED_CERT=yes

# [optional] loadbalance for accessing k8s from outside
[ex-lb]
10.0.2.1 LB_ROLE=backup EX_APISERVER_VIP=10.0.2.188 EX_APISERVER_PORT=8443
10.0.2.2 LB_ROLE=master EX_APISERVER_VIP=10.0.2.188 EX_APISERVER_PORT=8443

# [optional] ntp server for the cluster
[chrony]
#192.168.1.1

[all:vars]
# --------- Main Variables ---------------
# Cluster container-runtime supported: docker, containerd
CONTAINER_RUNTIME="docker"

# Network plugins supported: calico, flannel, kube-router, cilium, kube-ovn
CLUSTER_NETWORK="calico"

# Service proxy mode of kube-proxy: 'iptables' or 'ipvs'
PROXY_MODE="ipvs"

# K8S Service CIDR, not overlap with node(host) networking
SERVICE_CIDR="192.168.0.0/16"

# Cluster CIDR (Pod CIDR), not overlap with node(host) networking
CLUSTER_CIDR="10.10.0.0/16"

# NodePort Range
NODE_PORT_RANGE="30000-60000"

# Cluster DNS Domain
CLUSTER_DNS_DOMAIN="ljk.local."

# -------- Additional Variables (don't change the default value right now) ---
# Binaries Directory
bin_dir="/usr/local/bin"

# CA and other components cert/key Directory
ca_dir="/etc/kubernetes/ssl"

# Deploy Directory (kubeasz workspace)
base_dir="/etc/ansible"

验证配置是否成功:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
$ansible all -m ping    
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details # 这个警告是因为[kube-master]、[kube-node]、[ex-lb]组名有非法字符 “-”
10.0.1.2 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
10.0.2.2 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
10.0.2.3 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
10.0.2.1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
10.0.1.1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
10.0.1.3 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
10.0.1.4 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}

开始安装

如果你对集群安装流程不熟悉,请阅读项目首页 安装步骤 讲解后分步安装,并对 每步都进行验证

1

安装kubectl

https://kubernetes.io/zh/docs/tasks/tools/install-kubectl/

https://developer.aliyun.com/mirror/kubernetes?spm=a2c6h.13651102.0.0.3e221b11Qo8aZk

kubectl 详解

https://kubernetes.io/zh/docs/reference/kubectl/overview/

https://kubernetes.io/docs/reference/kubectl/overview/

1
kubectl [command] [TYPE] [NAME] [flags]

command:指定要对一个或多个资源执行的操作,例如 create、get、describe、delete
TYPE:指定资源类型。不区分大小写, 可以指定单数、复数或缩写形式。例如,以下命令输出相同的结果:

1
2
3
kubectl get pod pod1
kubectl get pods pod1
kubectl get po pod1

NAME:指定资源的名称。名称区分大小写。 如果省略名称,则显示所有资源的详细信息

1
2
3
4
5
6
# 类型相同的资源 TYPE1 name1 name2 name3...
kubectl get pod example-pod1 example-pod2
# 多个资源类型 TYPE1/name1 TYPE1/name2 TYPE2/name3 ...
kubectl get pod/example-pod1 replicationcontroller/example-rc1
# 用一个或多个文件指定资源 -f file1 -f file2 -f file3...
kubectl get -f ./pod.yaml

flags:指定可选的参数。例如,可以使用-s或-server指定Kubernetes API服务器的地址和端口

从命令行指定的参数优先级最高

基本命令

1
2
3
4
5
6
7
8
create        # Create a resource from a file or from stdin.
expose # Take a replication controller, service, deployment or pod and expose it as a new Kubernetes Service
run # Run a particular image on the cluster
set # Set specific features on objects
explain # 资源的详细信息
get # 显示一个或多个资源
edit # Edit a resource on the server
delete # Delete resources by filenames, stdin, resources and names, or by resources and label selector
1
2
3
kubectl get
[(-o|--output=)json|yaml|wide|custom-columns=...|custom-columns-file=...|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=...]
(TYPE[.VERSION][.GROUP] [NAME | -l label] | TYPE[.VERSION][.GROUP]/NAME ...) [flags] [options]

部署命令

1
2
3
rollout       Manage the rollout of a resource
scale Set a new size for a Deployment, ReplicaSet or Replication Controller
autoscale Auto-scale a Deployment, ReplicaSet, or ReplicationController

集群管理命令

1
2
3
4
5
6
7
certificate   Modify certificate resources.
cluster-info Display cluster info
top Display Resource (CPU/Memory/Storage) usage.
cordon Mark node as unschedulable
uncordon Mark node as schedulable
drain Drain node in preparation for maintenance
taint Update the taints on one or more nodes

故障处理和调试命令

1
2
3
4
5
6
7
8
9
describe      Show details of a specific resource or group of resources
logs Print the logs for a container in a pod
attach Attach to a running container
exec Execute a command in a container
port-forward Forward one or more local ports to a pod
proxy Run a proxy to the Kubernetes API server
cp Copy files and directories to and from containers.
auth Inspect authorization
debug Create debugging sessions for troubleshooting workloads and nodes

高级命令

1
2
3
4
5
6
diff          Diff live version against would-be applied version
apply Apply a configuration to a resource by filename or stdin
patch Update field(s) of a resource
replace Replace a resource by filename or stdin
wait Experimental: Wait for a specific condition on one or many resources.
kustomize Build a kustomization target from a directory or a remote url.

设置命令

1
2
3
label         Update the labels on a resource
annotate Update the annotations on a resource
completion Output shell completion code for the specified shell (bash or zsh)

其他命令

1
2
3
4
5
api-resources Print the supported API resources on the server
api-versions Print the supported API versions on the server, in the form of "group/version"
config Modify kubeconfig files
plugin Provides utilities for interacting with plugins.
version Print the client and server version information

alpha

convert

options

输出选项

Formatting output

1
kubectl [command] [TYPE] [NAME] -o <output_format>

Sorting list objects

1
kubectl [command] [TYPE] [NAME] --sort-by=<jsonpath_exp>

示例:常用操作

示例:创建和使用插件

资源

1
kubectl api-resources

kubeadm 提供了kubeadm initkubeadm join ,可以快速创建k8s集群。

kubeadm 通过执行必要的操作来启动和运行最小可用集群。按照设计,它只关注启动引导,而非配置机器。

我们希望在 kubeadm 之上构建更高级别以及更加合规的工具,理想情况下,使用 kubeadm 作为所有部署工作的基准将会更加易于创建一致性集群。

安装各种 “锦上添花” 的扩展,例如 Kubernetes Dashboard、监控方案、以及特定云平台的扩展,都不在讨论范围内。

安装kubeadm

参考:https://developer.aliyun.com/mirror/kubernetes?spm=a2c6h.13651102.0.0.3e221b11Qo8aZk

kubeadm

1
kubeadm [command] [flags]

command:

1
2
3
4
5
6
7
8
9
10
11
alpha           # kubeadm 处于测试阶段的命令,尽量不要用,`kubeadm alpha --help`查看有哪些命令
certs # 处理kubernetes证书
completion # bash 命令补全,需要安装 bash-completion
config # 管理 kubeadm 集群的配置,该配置保留在集群的 ConfigMap 中
help # Help about any command
init # 设置一个Kubernetes控制平面
join # 将节点加入到k8s集群
reset # 还原使用`kubeadm init`或者`kubeadm join`对系统产生的环境变化
token # 管理 token
upgrade # 升级 k8s 版本
version # 查看版本信息

flags:

1
2
3
4
5
6
7
8
9
--add-dir-header	# 如果为true,则将文件目录添加到日志消息的头部
-h, --help
--log-file string # 如果非空,则使用此日志文件
--log-file-max-size uint # 定义日志文件可以增长到的最大大小。单位是字节。当该值为0时,表示不限制文件的最大大小。1800(默认)
--one-output # 如果为真,则只将日志写入其本机的严重级别(vs也写入每个较低的严重级别)
--rootfs string # 到“真实的”主机根文件系统的路径。
--skip-headers # 如果为true,则避免在日志消息中使用头前缀
--skip-log-headers # 如果为true,在打开日志文件时避免头文件
-v, --v Level # 日志级别详细程度的编号

kubeadm completion

让kubeadm命令支持自动补全,只支持bash和zsh两种环境。
kubeadm completion bash 打印的脚本加载到环境变量即可:

1
2
3
4
5
6
7
yum install bash-completion -y
touch /etc/profile.d/kubeadm_completion.sh
kubeadm completion bash > /etc/profile.d/kubeadm_completion.sh
exit # 重新登录终端

[root@master01 ~]$kubeadm # tab键就会出现命令提示
alpha certs completion config help init join reset token upgrade version

kubeadm init

此命令初始化一个 Kubernetes 控制平面节点

参考:https://kubernetes.io/zh/docs/reference/setup-tools/kubeadm/kubeadm-init

kubeadm init 执行流程:

  1. 检查系统状态,有的检查只报错,有的检查会退出流程
  2. 生成自签名CA(可用使用用户提供的现有CA)为集群中的每个组件设置身份,默认存放在 /etc/kubernetes/kpi
  3. 在 /etc/kubernetes/ 中为 kubelet、controller-manger 和 scheduler 编写配置文件,让它们可以连接API Server,每个文件都需要有自己的标识。同时还需要为管理用途编写文件 admin.conf
  4. alpha相关,略…
  5. 为 API Server、controller-manager 和 scheduler 生成静态的 manifest 文件。如果没有提供外部etcd,也会为 etcd 生成一个额外的 Pod manifest 文件。
    静态 Pod 的 manifest 文件将会写入 /etc/kubernetes/manifest,kubelet监控这个目录,在启动时判断是否生成Pod。
    一旦控制平面 Pod 启动并运行,kubeadm init 将会继续运行
  6. alpha相关,略…
  7. 将标签和 taint 应用到 master 节点,这样就不会有额外的工作负载运行在该节点上
  8. 生成 token 以让额外的 node 能够将它们自己注册到这个 master,默认有效期24小时
  9. 创建所有必需的配置让 node 能够通过 Bootstrap Token 和 TLS Bootstrap 机制来加入集群
    1. 编写一个 ConfigMap 来提供加入集群所需的所有信息,并设置相关的 RBAC 访问规则
    2. 让 Bootstrap Token 能够访问 CSR 鉴权 API
    3. 为所有新的 CSR 请求配置 auto-approval
  10. 安装内部的 DNS 服务(默认CoreDNS),通过 Api Server 安装 kube-proxy 插件组件
    请注意:就算部署了 DNS 服务,在安装 CNI 之前它也不会被调度到 node 上
  11. alpha相关,略…
1
2
kubeadm init [command]
kubeadm init [flags]

command:

1
phase	# 使用此命令调用init工作流的单个阶段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
kubeadm init phase [command]
# command:
addon # Install required addons for passing Conformance tests
bootstrap-token # Generates bootstrap tokens used to join a node to a cluster
certs # Certificate generation
control-plane # 生成建立控制平面所需的所有静态pod清单文件
etcd # Generate static Pod manifest file for local etcd
kubeconfig # 生成建立控制平面所需的所有kubeconfig文件和管理kubeconfig文件
kubelet-finalize # Updates settings relevant to the kubelet after TLS bootstrap
kubelet-start # Write kubelet settings and (re)start the kubelet
mark-control-plane # Mark a node as a control-plane
preflight # Run pre-flight checks
upload-certs # Upload certificates to kubeadm-certs
upload-config # Upload the kubeadm and kubelet configuration to a ConfigMap

# 每个命令都可以使用--help查询帮助,例如:`kubeadm init phase addon --help`

flags:标星的是需要指定的,其他没有标星的一般情况下使用默认值即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
★ --apiserver-advertise-address string	# K8S API Server 将要监听的监听的 IP 地址,设置为master的IP,默认自动探测
★ --apiserver-bind-port int32 # API Server 绑定的端口,默认为 6443
--apiserver-cert-extra-sans strings # 可选的证书额外信息,用于指定 API Server 的服务器证书。可以是 IP 地址也可以是 DNS 名称
--cert-dir string # 证书的存储路径,缺省路径为 /etc/kubernetes/pki
--certificate-key string # 定义一个用于加密 kubeadm-certs Secret 中的控制平台证书的密钥
--config string # kubeadm 配置文件的路径
★ --control-plane-endpoint string # 为控制平面指定一个稳定的 IP 地址或 DNS 名称,即配置一个可以长期使用且是高可用的 VIP 或者域名,k8s 多 master 高可用基于此参数实现
--cri-socket string # 要连接的 CRI(容器运行时接口:Container Runtime Interface)套接字的路径。如果为空,则 kubeadm 将尝试自动检测此值;仅当安装了多个 CRI 或具有非标准 CRI 插槽时,才使用此选项
--dry-run # 不要应用任何更改;只是输出将要执行的操作,其实就是测试运行
--experimental-patches string # 用于存储 kustomize 为静态 pod 清单所提供的补丁的路径
--feature-gates string # 一组用来描述各种功能特性的键值(key=value)对。选项是:IPv6DualStack=true|false (ALPHA - default=false)
--ignore-preflight-errors strings # 可以忽略检查过程 中出现的错误信息,比如忽略 swap,如果为 all 就忽略所有
★ --image-repository string # 设置用于拉取控制平面镜像的容器仓库,默认为 k8s.gcr.io
★ --kubernetes-version string # 为控制平面选择一个特定的 Kubernetes 版本,默认为 stable-1
--node-name string # 指定master节点的名称,默认使用hostname
★ --pod-network-cidr string # 设置 pod ip 地址范围, control plane 会自动将 网络发布到其他节点的node,让其上启动的容器使用此网络,flannel插件的默认值是 10.244.0.0/16
★ --service-cidr string # 指定service 的IP 范围. (default "10.96.0.0/12")
--service-dns-domain string # 指定 service 的 dns 后缀, e.g. "myorg.internal". (default "cluster.local")
--skip-certificate-key- # 不打印 control-plane 用于加密证书的key.
--skip-phases strings # 跳过指定的阶段(phase)
--skip-token-print # 不打印 kubeadm init 生成的 default bootstrap token
--token string # 指定 node 和control plane 之间,简历双向认证的token ,格式为 [a-z0-9]{6}\.[a-z0-9]{16} - e.g. abcdef.0123456789abcdef
--token-ttl duration # token 自动删除的时间间隔。 (e.g. 1s, 2m, 3h). 如果设置为 '0', token 永不过期 (default 24h0m0s)
--upload-certs # 上传 control-plane 证书到 kubeadm-certs Secret

k8s中有三个网段:node、service、pod,这三个网段千万不要冲突,否则通信会出现问题

范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 多控制平面(多个master节点)
# 多个master通过HAProxy配置的负载均衡,再通过keepalived配置HAProxy的高可用,假设VIP为 10.0.0.1/24
kubeadm init --apiserver-advertise-address=10.0.0.71 \
--control-plane-endpoint=10.0.0.1 \
--apiserver-bind-port=6443 \
--kubernetes-version=v1.20.2 \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.10.0.0/16 \
--image-repository=registry.aliyuncs.com/google_containers

# 单控制平面(一个master节点)
# 对于单控制平面,controller-plane-endpoint默认同apiserver-advertise-address
kubeadm init --apiserver-advertise-address=10.0.0.71 \
--apiserver-bind-port=6443 \
--kubernetes-version=v1.20.2 \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.10.0.0/16 \
--image-repository=registry.aliyuncs.com/google_containers

kubeadm join

此命令用来初始化 Kubernetes 节点并将其加入集群

在执行完 kubeadm init 后,会在终端打印以后加入此集群时需要执行的kubeadm join 命令

参考:https://kubernetes.io/zh/docs/reference/setup-tools/kubeadm/kubeadm-join/

当节点加入 kubeadm 初始化的集群时,我们需要建立双向信任。 这个过程可以分解为发现TLS 引导两部分。

通常两个部分会使用相同的令牌。 在这种情况下可以使用 –token 参数,而不是单独指定每个令牌。

1
2
kubeadm join [api-server-endpoint] [flags]
kubeadm join [command]

command:

1
phase	# 使用此命令可以调用连接工作流的单个阶段

api-server-endpoint:控制平面的IP,如果是单控制平面,就是master节点的IP,如果是多控制平面,就是VIP

flags:

1

kubeadm alpha

kubeadm 处于测试阶段的命令,尽量不要用,kubeadm alpha --help 查看有哪些命令,v1.20.2版本中只有一个:kubeconfig

kubeadm certs

1
kubeadm certs [command]

command:

1
2
3
4
certificate-key		# 生成证书密钥
check-expiration # 检查Kubernetes集群的证书过期情况
generate-csr # 生成密钥和证书签名请求
renew # 为Kubernetes集群更新证书
1
2
3
4
5
kubeadm certs check-expiration [flags]
# flags:
--cert-dir string
--config string
--kubeconfig string
1
2
3
4
5
kubeadm certs generate-csr [flags]
# flags:
--cert-dir string
--config string
--kubeconfig-dir string
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
kubeadm certs renew [command]
# command:
admin.conf # 更新嵌入在kubeconfig文件中的证书,供管理员和kubeadm本身使用
all # 续期所有可用证书
apiserver # 更新服务Kubernetes API的证书
apiserver-etcd-client # 更新apiserver访问etcd时使用的证书
apiserver-kubelet-client # 更新证书以便API服务器连接到kubelet
controller-manager.conf # 更新嵌入在kubeconfig文件中的证书,以便控制器管理器使用
etcd-healthcheck-client # 将活动探测的证书更新到healthcheck etcd
etcd-peer # 为etcd节点之间的通信更新证书
etcd-server # 续证供etcd使用
front-proxy-client # 更新前端代理客户端证书
scheduler.conf # 更新kubeconfig文件中嵌入的证书,以便调度器管理器使用

# 每个命令都可以使用 --help 查询帮助,例如:`kubeadm certs renew admin.conf --help`

kubeadm config

kubeadm init 执行期间,kubeadm 将 ClusterConfiguration 对象上传到你的集群的 kube-system 名字空间下 名为 kubeadm-config 的 ConfigMap 对象中。 然后在 kubeadm joinkubeadm resetkubeadm upgrade 执行期间读取此配置。 要查看此 ConfigMap,请调用 kubectl get cm -o yaml -n kube-system kubeadm-config

你可以使用 kubeadm config print 命令打印默认配置, 并使用 kubeadm config migrate 命令将旧版本的配置转化成新版本。 kubeadm config images listkubeadm config images pull 命令可以用来列出并拉取 kubeadm 所需的镜像。

1
2
kubeadm config [command]
kubeadm config [flags]

command:

1
2
3
images	# 与kubeadm使用的容器镜像交互
migrate # 将本地旧版本的配置对象转换为最新支持的版本,而无需变更集群中的任何内容
print # 打印对象
1
2
3
4
kubeadm config images [command]	[flags]
# command:
list # 打印 kubeadm 要使用的镜像列表。配置文件用于自定义任何镜像或镜像存储库。
pull # 拉取 kubeadm 使用的镜像
1
2
3
4
5
6
7
8
kubeadm config images list [flags]
# flags
--allow-missing-template-keys
--config string
-o, --experimental-output string
--feature-gates string
--image-repository string
--kubernetes-version string
1
2
3
4
5
6
7
kubeadm config images pull [flags]
# flags
--config string # kubeadm 配置文件的路径
--cri-socket string
--feature-gates string
--image-repository string
--kubernetes-version string
1
2
3
4
kubeadm config migrate [flags]
# flags:
--new-config string # 使用新的 API 版本生成的 kubeadm 配置文件的路径。默认输出到stdout。
--old-config string # 使用旧 API 版本且应转换的 kubeadm 配置文件的路径。此参数是必需的
1
2
3
4
kubeadm config print [command]
# command:
init-defaults # 打印默认的初始化配置,可以用于`kubeadm init`
join-defaults # 打印默认连接配置,可以用于`kubeadm join`
1
2
3
4
kubeadm config print init-defaults [flags]
kubeadm config print join-defaults [flags]
# flags
--component-configs strings

flags:

1
--kubeconfig string		# 与集群通信时要使用的kubeconfig文件。(默认/etc/kubernetes/admin.conf)

kubeadm reset

kubeadm reset 负责从使用 kubeadm initkubeadm join 命令创建的文件中清除节点本地文件系统。对于控制平面节点,reset 还从 etcd 集群中删除该节点的本地 etcd 堆成员,还从 kubeadm ClusterStatus 对象中删除该节点的信息。 ClusterStatus 是一个 kubeadm 管理的 Kubernetes API 对象,该对象包含 kube-apiserver 端点列表。

kubeadm reset phase 可用于执行上述工作流程的各个阶段。 要跳过阶段列表,你可以使用 –skip-phases 参数,该参数的工作方式类似于 kubeadm joinkubeadm init 阶段运行器

“reset” 执行以下阶段:

1
2
3
4
preflight              Run reset pre-flight checks
update-cluster-status Remove this node from the ClusterStatus object.
remove-etcd-member Remove a local etcd member.
cleanup-node Run cleanup node.
1
2
kubeadm reset [command]
kubeadm reset [flags]

command:

1
phase	# 调用重置工作流的单个阶段
1
2
3
4
5
6
kubeadm reset phase [command]
# command
cleanup-node # Run cleanup node.
preflight # Run reset pre-flight checks
remove-etcd-member # Remove a local etcd member.
update-cluster-status # Remove this node from the ClusterStatus object.

flags:

1
2
3
4
5
6
--cert-dir string	# 存储证书的目录路径。需要清空此目录。默认"/etc/kubernetes/pki"
--cri-socket string # 要连接的 CRI 套接字的路径。如果为空,则 kubeadm 将尝试自动检测此值;仅当安装了多个CRI 或具有非标准 CRI 插槽时,才使用此选项
-f, --force # 在不提示确认的情况下重置节点
--ignore-preflight-errors strings # 忽略检查过程中出现的错误信息,比如swap,如果为all就忽略所有
--kubeconfig string # 与集群通信时使用的 kubeconfig 文件,默认 /etc/kubernetes/admin.conf
--skip-phases strings # 要跳过的阶段列表,四个阶段

注意:如果使用了外部 etcd,kubeadm reset 将不会删除任何 etcd 中的数据

kubeadm token

用于管理 kubeadm join 使用的令牌

使用 kubeadm init 默认生成的token有效期24小时

1
2
3
4
5
6
7
8
9
10
# 生成新 token
$kubeadm token create --print-join-command
kubeadm join 10.0.0.171:6443 --token mud4vy.ygs3zdmuz6rwggrt --discovery-token-ca-cert-hash sha256:83da17177796380c6038dd8a76bc7050fd9c3c6b55d53a7f7a652817cc73c8e6
# 查看目前有效的token
$kubeadm token list
TOKEN TTL EXPIRES USAGES DESCRIPTION EXTRA GROUPS
mud4vy.ygs3zdmuz6rwggrt 23h 2021-01-23T23:46:03+08:00 authentication,signing <none> system:bootstrappers:kubeadm:default-node-token
# 查看 hash
$openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
83da17177796380c6038dd8a76bc7050fd9c3c6b55d53a7f7a652817cc73c8e6

kubeadm upgrade

用于升级 Kubernetes 集群到新版本

kubeadm version

用于打印 kubeadm 的版本信息

kubeadm help

部署k8s集群

部署规划图

学习环境,简单部署,准备三台主机,都是centos7

角色 主机名 ip地址
master1 master01.ljk.cn 10.0.0.71/24
node1 node01.ljk.cn 10.0.0.72/24
node2 node02.ljk.cn 10.0.0.73/24

安装docker

注意:kubernetes对docker的版本有要求,最新版本的docker一般来讲都不兼容

经过测试:kubernetes v1.20.2 最高支持 docker v19.03

在三台主机上均执行以下步骤:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum makecache fast
yum list docker-ce.x86_64 --showduplicates | sort -r # 搜索可用版本
yum install -y docker-ce-19.03.9 # 安装指定版本
# 加速 和 优化
mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://3417nt4m.mirror.aliyuncs.com"],
"exec-opts":["native.cgroupdriver=systemd"]
}
EOF
systemctl enable --now docker.service

安装Kubernetes

在三台主机上均执行以下步骤:

1
2
3
4
5
6
7
8
9
10
11
12
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
setenforce 0
yum install -y kubelet kubeadm kubectl
systemctl enable --now kubelet

部署dns,或者直接修改/etc/hosts

在三台主机上均执行以下步骤:

1
2
3
4
5
# cat /etc/hosts
...
10.0.0.71 master01.ljk.cn
10.0.0.72 node01.ljk.cn
10.0.0.73 node02.ljk.cn

kubeadm init 初始化

集群初始化,而且集群初始化只需要初始化一次

注意:kubeadm init 必须在master节点上运行,任意一master节点即可

1
2
3
4
# 提前下载组件镜像,这一步可以不用执行,init的时候会自动下载,但是下载时间一般很长,最好还是提前下载
kubeadm config images pull --image-repository=registry.aliyuncs.com/google_containers --kubernetes-version=v1.20.2
# 预检查一下,出现问题则修复
[root@master01 docker]$kubeadm init phase preflight

初始化,两种方式:

1
2
3
4
5
6
7
8
# 方式一
[root@master01 ~]$kubeadm init --apiserver-advertise-address=10.0.0.71 \
--apiserver-bind-port=6443 \
--kubernetes-version=v1.20.2 \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.10.0.0/16 \
--image-repository=registry.aliyuncs.com/google_containers \
--ignore-preflight-errors=NumCPU # 学习环境,忽略cpu数量的检查
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# 方式二
[root@master01 ~]$kubeadm config print init-defaults > /etc/kubernetes/kubeadmin-init.yaml
# 修改advertiseAddress、imageRepository、kubernetesVersion、dnsDomain、serviceSubnet
[root@master01 ~]$cat /etc/kubernetes/kubeadmin-init.yaml
apiVersion: kubeadm.k8s.io/v1beta2
bootstrapTokens:
- groups:
- system:bootstrappers:kubeadm:default-node-token
token: abcdef.0123456789abcdef
ttl: 24h0m0s
usages:
- signing
- authentication
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 10.0.0.71
bindPort: 6443
nodeRegistration:
criSocket: /var/run/dockershim.sock
name: master01.ljk.cn
taints:
- effect: NoSchedule
key: node-role.kubernetes.io/master
---
apiServer:
timeoutForControlPlane: 4m0s
apiVersion: kubeadm.k8s.io/v1beta2
certificatesDir: /etc/kubernetes/pki
clusterName: kubernetes
#controlPlaneEndpoint: 10.0.0.1:6443 #多控制平面开启此项,基于 VIP 的 Endpoint
controllerManager: {}
dns:
type: CoreDNS
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.aliyuncs.com/google_containers
kind: ClusterConfiguration
kubernetesVersion: v1.20.2
networking:
dnsDomain: ljk.local
podSubnet: 10.244.0.0/16
serviceSubnet: 10.10.0.0/16
scheduler: {}

[root@master01 docker]$kubeadm init --config=/etc/kubernetes/kubeadmin-init.yaml --ignore-preflight-errors=NumCPU # 忽略检查cpu核心数,生产环境不要忽略
...
...
...
Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 10.0.0.71:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:b794ecc7f2fc825b58e4e2108eab0dfa603c3d861de55bcc8c437949bed83fec

# 按照init成功后的提示
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
# 如果是root用户,也可以
export KUBECONFIG=/etc/kubernetes/admin.conf

# 安装网络插件 flannel,参考:https://github.com/coreos/flannel
# 这个链接可能需要科学上网
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

补充:如果是多控制平面,kubeadm init 需要添加 –control-plane-endpoint 参数,设置访问多个master的VIP,通常是 keepalived+HAProxy 配置多个master的高可用

1
2
3
4
5
6
7
8
[root@master01 ~]$kubeadm init --apiserver-advertise-address=10.0.0.71 \
--control-plane-endpoint=10.0.0.1 \
--apiserver-bind-port=6443 \
--kubernetes-version=v1.20.2 \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.10.0.0/16 \
--image-repository=registry.aliyuncs.com/google_containers \
--ignore-preflight-errors=NumCPU

kubeadm join node加入k8s集群

加入集群的 kubeadm join 命令在 kubeadm init 完成后会自动打印出来,如果将来token和hash过期失效了,使用 kubeadm token create --print-join-command 重新生成即可

1
2
3
4
5
6
7
8
# node1
[root@node01 kubernetes]$kubeadm join 10.0.0.71:6443 \
--token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:b794ecc7f2fc825b58e4e2108eab0dfa603c3d861de55bcc8c437949bed83fec
# node2
[root@node02 ~]$kubeadm join 10.0.0.71:6443 \
--token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:b794ecc7f2fc825b58e4e2108eab0dfa603c3d861de55bcc8c437949bed83fec

查看是否加入成功:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@master01 ~]$kubectl get nodes
NAME STATUS ROLES AGE VERSION
master01.ljk.cn Ready control-plane,master 53m v1.20.2
node01.ljk.cn Ready <none> 6m24s v1.20.2
node02.ljk.cn Ready <none> 10m v1.20.2

# 在每个节点上都生成一个flannel网卡,或者说是网络隧道,保障集群内部的通信
[root@master01 ~]$ip a # master
...
4: flannel.1: <BROADCAST,MULTICAST> mtu 1450 qdisc noop state DOWN group default
link/ether 26:69:fd:2f:7a:3f brd ff:ff:ff:ff:ff:ff
[root@node01 kubernetes]$ip a # node1
...
4: flannel.1: <BROADCAST,MULTICAST> mtu 1450 qdisc noop state DOWN group default
link/ether a2:74:d6:61:d5:5c brd ff:ff:ff:ff:ff:ff
[root@node02 ~]$ip a # node2
...
4: flannel.1: <BROADCAST,MULTICAST> mtu 1450 qdisc noop state DOWN group default
link/ether fe:83:2b:fc:1e:01 brd ff:ff:ff:ff:ff:ff

部署Web服务 Dashboard

github地址:https://github.com/kubernetes/dashboard/releases

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 1.下载配置清单
$wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.1.0/aio/deploy/recommended.yaml
# 2.修改配置清单
$vim recommended.yaml
...
spec:
type: NodePort # 添加此行
ports:
- port: 443
targetPort: 8443
nodePort: 30002 # 添加此行
selector:
k8s-app: kubernetes-dashboard
...
# 3.创建资源对象
kubectl apply -f ./recommended.yaml
# 4.查看
$kubectl get pod -n kubernetes-dashboard
NAME READY STATUS RESTARTS AGE
dashboard-metrics-scraper-79c5968bdc-5dv7w 1/1 Running 0 88m
kubernetes-dashboard-7448ffc97b-rg77t 1/1 Running 0 88m
# 5.创建管理 dashboard 的 service 账号
$cat admin-user.yml
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard
$kubectl apply -f admin-user.yml
# 6.查看 admin-user 的 token
$kubectl get secrets -A | grep admin-user
$kubectl describe secrets -n kubernetes-dashboard admin-user-token-wpz7j
Name: admin-user-token-wpz7j
Namespace: kubernetes-dashboard
Labels: <none>
Annotations: kubernetes.io/service-account.name: admin-user
kubernetes.io/service-account.uid: 613c9277-f124-4622-88c9-714dc2479602

Type: kubernetes.io/service-account-token

Data
====
ca.crt: 1066 bytes
namespace: 20 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IjJ2THVKYzd4Q3hVeVI5QWVCMk5YUU5kbE9lRzJjZ1hHZkV0WndQUGczWmcifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlcm5ldGVzLWRhc2hib2FyZCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJhZG1pbi11c2VyLXRva2VuLXdwejdqIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImFkbWluLXVzZXIiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiI2MTNjOTI3Ny1mMTI0LTQ2MjItODhjOS03MTRkYzI0Nzk2MDIiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZXJuZXRlcy1kYXNoYm9hcmQ6YWRtaW4tdXNlciJ9.N7Hcf9JIgV5p_j8-YYJHMDrqGkGtsalTxbabTjXASyoR63gmvNmekPACQ9EDwu1MF2du3wkyReVb_aYD11tHw4XsNbfnoaytYqcQ9U8lhLXd8A7wlBnK8_EBa5-XP0-nRRSw7gUsG6s7xvrviWcndNO0nIUPgS--B1G8S-AR_Y0CJRzFF4FL0zhZvxCxSDwHO2OrjKpbxhuZOgzhOI_CXCEMghsCyUUFeNlRj2F-YulzVNLdJSzIh0UMyvoKVv6ylesRtyUJK8lo3tpcC0K4hTKsWYXHgibto024tT4D1KtYLqNhEhI4PkYogZQTsG3-ggVo5Nry5m8AL0CKCD0xoA

最后,打开浏览器,输入 https://10.0.0.171:30002/,除了10.0.0.171,10.0.0.71 和 10.0.0.72 也可以,然后copy 刚才生产的 admin-user 用户的 token,成功登陆

k8s 集群升级

小版本升级,一般不会有很大更改,经过充分测试,直接升级即可

大版本升级,风险较大,可以像小版本一样,经过测试,然后直接升级;但是更推荐以下升级方式:

  1. 在备用的服务器上再部署一套k8s集群,使用最新的k8s版本

  2. 把业务离线导入新的k8s集群

  3. 经过测试后,切换负载均衡到新的k8s集群

  4. 下线的旧k8s集群,直接重装系统,安装最新的ubuntu或者centos,然后作为node加入到新的k8s集群

  5. 升级完成

这种方法是比较稳妥的,只是成本比较高,需要有充足的备用的服务器,如果目前的k8s集群使用30台服务器,那备用的服务器差不多也得20台

升级 master

先升级 kubeadm,kubeadm 是k8s 升级的“准升证”

  1. 验证当 k8s 前版本

    1
    $kubeadm version
  2. 各 master 安装指定新版本 kubeadm

    1
    2
    3
    4
    $apt-cache madison kubeadm #查看 k8s 版本列表
    $apt-get install kubeadm=1.17.4-00 #安装新版本 kubeadm
    $kubeadm version #验证 kubeadm 版本
    $apt install kubelet=1.17.4-00 kubectl=1.17.4-00 # kubectl 和 kubelet 也升级一下
  3. kubeadm 升级命令使用帮助

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    $kubeadm upgrade --help
    Upgrade your cluster smoothly to a newer version with this command

    Usage:
    kubeadm upgrade [flags]
    kubeadm upgrade [command]

    Available Commands:
    apply Upgrade your Kubernetes cluster to the specified version
    diff Show what differences would be applied to existing static pod manifests. See also: kubeadm upgrade apply --dry-run
    node Upgrade commands for a node in the cluster
    plan Check which versions are available to upgrade to and validate whether your current cluster is upgradeable. To skip the internet check, pass in the optional [version] parameter
  4. 升级计划

    1
    kubeadm upgrade plan #查看升级计划

  5. 开始升级

    1
    2
    3
    $kubeadm upgrade apply v1.17.4 #master1
    $kubeadm upgrade apply v1.17.4 #master2
    $kubeadm upgrade apply v1.17.4 #master3

  6. 验证镜像

    1
    $docker image ls

    升级 node

升级客户端服务 kubectl kubelet

  1. 验证当前 node 版本信息

    1
    $kubectl get node
  2. 升级各 node 节点配置文件

    1
    $kubeadm upgrade node --kubelet-version v1.17.4		# master上执行
  3. 各 Node 节点升级 kubelet、kubeadm、kubectl 二进制包

    1
    $apt install kubelet=1.17.4-00 kubeadm=1.17.4-00 kubectl=1.17.4-00

测试运行 Nginx+Tomcat

以应用为中心

资源

apiserver 是 RESTful 风格的 https 服务器,通过apiserver对资源进行增删改查等管理操作。

所以每个资源都能以url的方式访问到:

1
2
3
4
5
domain:6643/apis/$GROUP_NAME/$VERSION/namespaces/$NAMESPACE/$NAME/$API_RESOURCE_NAME

domain:6643/api/$VERSION/namespaces/$NAMESPACE/$NAME/$API_RESOURCE_NAME
# 范例:
domain:6643/api/v1/namespaces/default/pods/demoapp-5f7d8f9847-tjn4v

apiserver以群组分区资源,群组化管理的api使得其可以更轻松地进行扩展,常用的api群组分为两类:
命名群组:/apis/$GROUP_NAME/$VERSION,例如/apis/apps/v1
核心群组core:简化了路径,/api/$VERSION,即 /api/v1

查看所有支持的资源:

1
2
3
4
5
kubectl api-resources							# 打印所有API资源
kubectl api-resources -o wide # 打印更多信息
kubectl api-resources --sort-by=name # 按“name"列排序
kubectl api-resources --namespaced=true # 过滤,namespaced 为true
kubectl api-resources --api-group=extensions # 过滤,api group 为 extensions

查看指定资源:

以下三种方式返回的数据是一样的:

1
2
3
4
5
6
7
# 方式一,这种方式最方便
kubectl get pods net-tes1 -o json|yaml
# 方式二
kubectl get --raw /api/v1/namespaces/default/pods/net-test1
# 方式三
kubectl proxy
curl 127.0.0.1:8001/api/v1/namespaces/default/pods/net-test1 # 另起一终端
1
2
3
4
5
6
$kubectl get pods net-test1 -o yaml
apiVersion: v1
kind: Pod
>metadata:
>spec:
>status:

以上返回的数据,每个字段表示的意义可以通过 kubectl explain 查询帮助

1
kubectl explain <type>.<fieldName>[.<fieldName>]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$kubectl explain pod.apiVersion
KIND: Pod
VERSION: v1

FIELD: apiVersion <string>

DESCRIPTION:
APIVersion defines the versioned schema of this representation of an
object. Servers should convert recognized schemas to the latest internal
value, and may reject unrecognized values. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources

# 范例
$kubectl explain pod.kind
$kubectl explain pod.metadata
$kubectl explain pod.spec
$kubectl explain pod.status
$kubectl explain pod.status.conditions
$kubectl explain pod.status.conditions.lastProbeTime

pod

资源的分类:

  1. 工作负载型资源(workload):Pod
    stateful:有状态;stateless:无状态
       Deployment:最著名的无状态应用编排工具,支持应用的自动扩容、缩荣、滚动更新、金丝雀发布等
       DaemonSet:编排无状态的系统应用
       StatefulSet:编排有状态应用,遗憾的是,没什么意义
       Operator:StatefulSet的下一代
       Job、Cronjob:作业和周期性作业
  2. 服务发现和负载均衡:Service、Ingress
  3. 配置和存储:ConfigMap/Secret、PVC/PV、Downward API
  4. namespace:命名空间也是一种资源,集群级别
  5. endpoint

资源的作用域,两种级别:

  1. 全局级别,或者说集群级别:整个k8s
  2. 命名空间级别:各种namespace,和php一样,也是为了避免重名

lease 租约

lease 是分布式系统中一个常见的概念,用于代表一个分布式租约。典型情况下,在分布式系统中需要去检测一个节点是否存活的时,就需要租约机制。

上图示例中的代码示例首先创建了一个 10s 的租约,如果创建租约后不做任何的操作,那么 10s 之后,这个租约就会自动过期。接着将 key1 和 key2 两个 key value 绑定到这个租约之上,这样当租约过期时 etcd 就会自动清理掉 key1 和 key2,使得节点 key1 和 key2 具备了超时自动删除的能力。

如果希望这个租约永不过期,需要周期性的调用 KeeyAlive 方法刷新租约。比如说需要检测分布式系统中一个进程是否存活,可以在进程中去创建一个租约,并在该进程中周期性的调用 KeepAlive 的方法。如果一切正常,该节点的租约会一致保持,如果这个进程挂掉了,最终这个租约就会自动过期。

在 etcd 中,允许将多个 key 关联在同一个 lease 之上,这个设计是非常巧妙的,可以大幅减少 lease 对象刷新带来的开销。试想一下,如果有大量的 key 都需要支持类似的租约机制,每一个 key 都需要独立的去刷新租约,这会给 etcd 带来非常大的压力。通过多个 key 绑定在同一个 lease 的模式,我们可以将超时间相似的 key 聚合在一起,从而大幅减小租约刷新的开销,在不失灵活性同时能够大幅提高 etcd 支持的使用规模。

Socket套接字

套接字Socket是进程间通信IPC的一种实现,允许位于不同主机(或同一主机)上不同进程之间进行通信和数据交换,SocketAPI出现于1983年 BSD 4.2实现

在建立通信连接的每一端,进程间的传输要有两个标志:IP地址和端口号,合称为套接字地址 socket address

客户机套接字地址定义了一个唯一的客户进程
服务器套接字地址定义了一个唯一的服务器进程

Socket API

封装了内核中所提供的socket通信相关的系统调用

Socket Domain:根据其所使用的地址

1
2
3
AF_INET		# Address Family,IPv4
AF_INET6 # IPv6
AF_UNIX # 同一主机上不同进程之间通信时使用

Socket Type:根据使用的传输层协议

1
2
3
SOCK_STREAM		# 流,tcp套接字,可靠地传递、面向连接
SOCK_DGRAM # 数据报,udp套接字,不可靠地传递、无连接
SOCK_RAW # 裸套接字,无须tcp或udp,APP直接通过IP包通信

客户/服务器程序的套接字函数

1
2
3
4
5
6
7
8
socket() 		# 创建一个套接字
bind() # 绑定IP和端口
listen() # 监听
accept() # 接收请求
connect() # 请求连接建立
write() # 发送
read() # 接收
close() # 关闭连接

http 协议及报文头部结构

Method 方法

请求方法,标明客户端希望服务器对资源执行的动作

  • GET: 从服务器获取一个资源
  • HEAD: 只从服务器获取文档的响应首部
  • POST: 向服务器输入数据,通常会再由网关程序继续处理
  • PUT: 将请求的主体部分存储在服务器中,如上传文件
  • DELETE: 请求删除服务器上指定的文档
  • TRACE: 追踪请求到达服务器中间经过的代理服务器
  • OPTIONS:请求服务器返回对指定资源支持使用的请求方法
  • CONNECT:建立一个到由目标资源标识的服务器的隧道
  • PATCH:用于对资源应用部分修改

status 状态码

参考资料:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status

1
2
3
4
5
1xx:100-101 信息提示
2xx:200-206 成功
3xx:300-307 重定向
4xx:400-415 错误类信息,客户端错误
5xx:500-505 错误类信息,服务器端错误
1
2
3
4
5
6
7
8
9
10
11
12
200: 成功,请求数据通过响应报文的entity-body部分发送;OK
301: 永久重定向;Moved Permanently
302: 临时重定向 Moved Temporarily
304: 客户端发出了条件式请求,但服务器上的资源未曾发生改变,则通过响应此响应状态码通知客户端;Not Modified
307: 浏览器内部重定向
401: 需要输入账号和密码认证方能访问资源;Unauthorized
403: 请求被禁止;Forbidden
404: 服务器无法找到客户端请求的资源;Not Found
500: 服务器内部错误;Internal Server Error
502: 代理服务器从后端服务器收到了一条伪响应,如无法连接到网关;Bad Gateway
503: 服务不可用,临时服务器维护或过载,服务器无法处理请求
504: 网关超时

关于301和302:

用户输入了你不希望输入的url或者说是没用的url,用301重定向,例如http转到https、旧域名转到新域名;
因为业务逻辑临时跳转,用302重定向,例如用户直接访问管理后台就临时跳转到登录页面

web相关工具

wget

1
wget [OPTION]... [URL]...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#启动
-V,-version 显示wget的版本后退出
-h,-help 打印语法帮助
-b,-background 启动后转入后台执行
-e,-execute=COMMAND 执行`.wgetrc'格式的命令,wgetrc格式参见/etc/wgetrc或~/.wgetrc

#记录和输入文件
-o,-output-file=FILE 把记录写到FILE文件中
-a,-append-output=FILE 把记录追加到FILE文件中
-d,-debug 打印调试输出
-q,-quiet 安静模式(没有输出)
-v,-verbose 冗长模式(这是缺省设置)
-nv,-non-verbose 关掉冗长模式,但不是安静模式
-i,-input-file=FILE 下载在FILE文件中出现的URLs
-F,-force-html 把输入文件当作HTML格式文件对待
-B,-base=URL 将URL作为在-F -i参数指定的文件中出现的相对链接的前缀
-sslcertfile=FILE 可选客户端证书
-sslcertkey=KEYFILE 可选客户端证书的KEYFILE
-egd-file=FILE 指定EGD socket的文件名

#下载
-bind-address=ADDRESS 指定本地使用地址(主机名或IP,当本地有多个IP或名字时使用)
-t,-tries=NUMBER 设定最大尝试链接次数(0 表示无限制).
-O -output-document=FILE 把文档写到FILE文件中
-nc,-no-clobber 不要覆盖存在的文件或使用.#前缀
-c,-continue 接着下载没下载完的文件
-progress=TYPE 设定进程条标记
-N,-timestamping 不要重新下载文件除非比本地文件新
-S,-server-response 打印服务器的回应
-spider 不下载任何东西
-T,-timeout=SECONDS 设定响应超时的秒数
-w,-wait=SECONDS 两次尝试之间间隔SECONDS秒
-waitretry=SECONDS 在重新链接之间等待1…SECONDS秒
-random-wait 在下载之间等待0…2*WAIT秒
-Y,-proxy=on/off 打开或关闭代理
-Q,-quota=NUMBER 设置下载的容量限制
-limit-rate=RATE 限定下载输率
#目录
-nd -no-directories 不创建目录
-x,-force-directories 强制创建目录
-nH,-no-host-directories 不创建主机目录
-P,-directory-prefix=PREFIX 将文件保存到目录 PREFIX/…
-cut-dirs=NUMBER 忽略 NUMBER层远程目录
#HTTP 选项
-http-user=USER 设定HTTP用户名为 USER.
-http-passwd=PASS 设定http密码为 PASS.
-C,-cache=on/off 允许/不允许服务器端的数据缓存 (一般情况下允许).
-E,-html-extension 将所有text/html文档以.html扩展名保存
-ignore-length 忽略 'Content-Length'头域
-header=STRING 在headers中插入字符串 STRING
-proxy-user=USER 设定代理的用户名为 USER
-proxy-passwd=PASS 设定代理的密码为 PASS
-referer=URL 在HTTP请求中包含 `Referer: URL'
-s,-save-headers 保存HTTP头到文件
-U,-user-agent=AGENT 设定代理的名称为 AGENT而不是 Wget/VERSION.
-no-http-keep-alive 关闭 HTTP活动链接 (永远链接).
-cookies=off 不使用 cookies.
-load-cookies=FILE 在开始会话前从文件 FILE中加载cookie
-save-cookies=FILE 在会话结束后将 cookies保存到 FILE文件中

#FTP 选项
-nr,-dont-remove-listing 不移走 `.listing'文件
-g,-glob=on/off 打开或关闭文件名的 globbing机制
-passive-ftp 使用被动传输模式 (缺省值).
-active-ftp 使用主动传输模式
-retr-symlinks 在递归的时候,将链接指向文件(而不是目录)

#递归下载
-r,-recursive 递归下载--慎用!
-l,-level=NUMBER 最大递归深度 (inf 或 0 代表无穷).
-delete-after 在现在完毕后局部删除文件
-k,-convert-links 转换非相对链接为相对链接
-K,-backup-converted 在转换文件X之前,将之备份为 X.orig
-m,-mirror 等价于 -r -N -l inf -nr.
-p,-page-requisites 下载显示HTML文件的所有图片

#递归下载中的包含和不包含(accept/reject)
-A,-accept=LIST 分号分隔的被接受扩展名的列表
-R,-reject=LIST 分号分隔的不被接受的扩展名的列表
-D,-domains=LIST 分号分隔的被接受域的列表
-exclude-domains=LIST 分号分隔的不被接受的域的列表
-follow-ftp 跟踪HTML文档中的FTP链接
-follow-tags=LIST 分号分隔的被跟踪的HTML标签的列表
-G,-ignore-tags=LIST 分号分隔的被忽略的HTML标签的列表
-H,-span-hosts 当递归时转到外部主机
-L,-relative 仅仅跟踪相对链接
-I,-include-directories=LIST 允许目录的列表
-X,-exclude-directories=LIST 不被包含目录的列表
-np,-no-parent 不要追溯到父目录

常用选项:

1
2
3
4
5
-q 静默模式
-c 断点续传
-P /path 保存在指定目录
-O filename 保存为指定文件名,filename 为 - 时,发送至标准输出
--limit-rate= 指定传输速率,单位K,M等

curl

curl是基于URL语法在命令行方式下工作的文件传输工具,它支持FTP,FTPS,HTTP,HTTPS,GOPHER,TELNET,DICT,FILE及LDAP等协议。curl支持HTTPS认证,并且支持HTTP的POST、PUT等方法,FTP上传,kerberos认证,HTTP上传,代理服务器,cookies,用户名/密码认证,下载文件断点续传,上载文件断点续传,http代理服务器管道( proxy tunneling),还支持IPv6,socks5代理服务器,通过http代理服务器上传文件到FTP服务器等,功能十分强大

1
curl [options] [URL...]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
-A/--user-agent <string> 设置用户代理发送给服务器
-e/--referer <URL> 来源网址
--cacert <file> CA证书 (SSL)
-k/--insecure 允许忽略证书进行 SSL 连接
--compressed 要求返回是压缩的格式
-H/--header "key:value” 自定义首部字段传递给服务器
-i 显示页面内容,包括报文首部信息
-I/--head 只显示响应报文首部信息
-D/--dump-header <file>将url的header信息存放在指定文件中
--basic 使用HTTP基本认证
-u/--user <user[:password]>设置服务器的用户和密码
-L 如果有3xx响应码,重新发请求到新位置
-O 使用URL中默认的文件名保存文件到本地
-o <file> 将网络文件保存为指定的文件中
--limit-rate <rate> 设置传输速度
-0/--http1.0 数字0,使用HTTP 1.0
-v/--verbose 更详细
-C 选项可对文件使用断点续传功能
-c/--cookie-jar <file name> 将url中cookie存放在指定文件中
-x/--proxy <proxyhost[:port]> 指定代理服务器地址
-X/--request <command> 向服务器发送指定请求方法
-U/--proxy-user <user:password> 代理服务器用户和密码
-T 选项可将指定的本地文件上传到FTP服务器上
--data/-d 方式指定使用POST方式传递数据
-s --silent Silent mode
-b name=data 从服务器响应set-cookie得到值,返回给服务器
-w <format> 显示相应的指定的报文信息,如:%{http_code},%{remote_ip}等
-m, --max-time <time> 允许最大传输时间

httpie

httpie 工具是现代的 HTTP 命令行客户端,它能通过命令行界面与 Web 服务进行交互。它提供一个简单的 http 命令,允许使用简单而自然的语法发送任意的 HTTP 请求,并会显示彩色的输出

httpie 能用于测试、调试及与 HTTP 服务器交互

  • 具表达力的和直观语法
  • 格式化的及彩色化的终端输出
  • 内置 JSON 支持
  • 表单和文件上传
  • HTTPS、代理和认证任意请求数据
  • 自定义头部
  • 持久化会话
  • 类似 wget 的下载
  • 支持 Python 2.7 和 3.x

官方网站:https://httpie.org
安装:基于EPEL(CentOS 8 目前还不支持)

1
[root@centos7 ~]#yum install httpie -y

范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 显示信息(包含响应头200)
http www.magedu.com

# 显示详细的请求(包含请求和返回头200)
http -v www.magedu.com

# 只显示Header
http -h www.magedu.com
http --head www.magedu.com
http --header www.magedu.com
http --headers www.magedu.com

# 只显示Body
http -b www.magedu.com
http --body magedu.com

# 下载文件
http -d www.magedu.com

# 模拟提交表单
http -f POST www.magedu.com username='wang'

# 请求删除的方法
http DELETE www.magedu.com

# 传递JSON数据请求(默认就是JSON数据请求)
http PUT www.magedu.com username='wang' password='magedu'

# 如果JSON数据存在不是字符串则用:=分隔,例如
http PUT www.magedu.com username='wang' password='magedu' age:=30 a:=true streets:='["a", "b"]'

# 模拟Form的Post请求, Content-Type: application/x-www-form-urlencoded;
charset=utf-8
http --form POST www.magedu.com username='wang'

# 模拟Form的上传, Content-Type: multipart/form-data
http -f POST www.magedu.com/jobs username='wang' file@~/test.pdf

# 修改请求头, 使用:分隔
http www.magedu.com User-Agent:magedu-agent/1.0 'Cookie:a=b;b=c' Referer:http://www.google.com/

# 认证
http -a username:password www.magedu.com
http -A basic -a username:password www.magedu.com

# 使用http代理
http --proxy=http:http://172.16.0.100:8081 proxy.magedu.com
http --proxy=http:http://user:pass@172.16.0.100:8081 proxy.magedu.com
http --proxy=https:http://172.16.0.100:8118 proxy.magedu.com
http --proxy=https:http://user:pass@172.16.0.100:8118 proxy.magedu.com

范例:查看信息及相应头

1
2
3
4
5
6
7
8
9
10
11
12
[root@centos7 ~]#http 192.168.8.8/test.html
HTTP/1.1 200 OK
Accept-Ranges: bytes
Connection: Keep-Alive
Content-Length: 30
Content-Type: text/html; charset=UTF-8
Date: Thu, 07 Nov 2019 09:09:34 GMT
ETag: "1e-596be05bc9a34"
Keep-Alive: timeout=5, max=100
Last-Modified: Thu, 07 Nov 2019 09:09:27 GMT
Server: Apache/2.4.37 (centos)
<strong>马哥教育</strong>

范例:查看请示和响应头部及信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@centos7 ~]#http -v 192.168.8.8/test.html
GET /test.html HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: 192.168.8.8
User-Agent: HTTPie/0.9.4

HTTP/1.1 200 OK
Accept-Ranges: bytes
Connection: Keep-Alive
Content-Length: 30
Content-Type: text/html; charset=UTF-8
Date: Thu, 07 Nov 2019 09:09:39 GMT
ETag: "1e-596be05bc9a34"
Keep-Alive: timeout=5, max=100
Last-Modified: Thu, 07 Nov 2019 09:09:27 GMT
Server: Apache/2.4.37 (centos)
<strong>马哥教育</strong>

范例:查看响应报文头部

1
2
3
4
5
6
7
8
9
10
11
[root@centos7 ~]#http HEAD http://www.magedu.com
HTTP/1.1 200 OK
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html; charset=UTF-8
Date: Thu, 07 Nov 2019 08:09:49 GMT
Link: <http://www.magedu.com/wp-json/>; rel="https://api.w.org/"
Link: <http://www.magedu.com/>; rel=shortlink
Server: Tengine
Vary: Accept-Encoding
Vary: Accept-Encoding, Cookie

范例: 查看请求和响应报文头部

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@centos7 ~]#http -p Hh http://www.magedu.com
GET / HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: www.magedu.com
User-Agent: HTTPie/0.9.4

HTTP/1.1 200 OK
Cache-Control: max-age=3, must-revalidate
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html; charset=UTF-8
Date: Thu, 07 Nov 2019 03:44:14 GMT
Server: Tengine
Transfer-Encoding: chunked
Vary: Accept-Encoding
Vary: Accept-Encoding, Cookie

范例:指定请求头部的首部字段

1
2
3
4
5
6
7
8
9
[root@centos7 ~]#http -p H http://www.magedu.com User-Agent:wangtest
Referer:http://www.baidu.com
GET / HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: www.magedu.com
Referer: http://www.baidu.com
User-Agent: wangtest

范例:下载资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#方法1
[root@centos7 ~]#http http://www.magedu.com/wp-content/uploads/2018/12/2018122312035677.png > logo.png
#方法2
[root@centos7 ~]#file logo.png
logo.png: PNG image data, 411 x 127, 8-bit/color RGBA, non-interlaced
[root@centos7 ~]#http --download http://www.magedu.com/wp-content/uploads/2018/12/2018122312035677.png
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: max-age=604800
Connection: keep-alive
Content-Length: 8983
Content-Type: image/png
Date: Thu, 07 Nov 2019 08:20:44 GMT
ETag: "5c1f79ac-2317"
Expires: Thu, 14 Nov 2019 08:20:44 GMT
Last-Modified: Sun, 23 Dec 2018 12:03:56 GMT
Server: Tengine
Vary: Accept-Encoding

Downloading 8.77 kB to "2018122312035677.png"
Done. 8.77 kB in 0.00091s (9.46 MB/s)

范例:用POST方法提交json格式的数据

1
[root@centos7 ~]#http http://www.magedu.com user=wang password=magedu

范例:用POST方法,指交表单数据

1
[root@centos7 ~]#http -f POST http://www.magedu.com user=wang password=magedu

压力测试工具

ab 来自httpd-tools包

1
ab [OPTIONS] URL

option:

  • -n:总请求数
  • -c:模拟的并发数
  • -k:以持久连接模式测试

运维三大职能:故障管理、变更管理、资源管理

什么是k8s?
k8s是部署在一群服务器之上的组件,将所有服务器整合成一个资源池,然后向客户端提供各种接口, 客户端只需要调用相应接口就可以管理容器,至于底层容器具体跑在哪台服务器,不可见也不需要关心

针对各种特定的业务,尤其是比较依赖工程师经验的业务(例如数据库集群宕机后的数据恢复、各种集群的扩缩容),可以将一系列复杂操作代码化,这个代码在k8s中就叫operator,只要用好各种operator,就可以方便高效的解决各种问题,这样,运维工程师的主要工作就变成了维护k8s,确保k8s自身能够良好运行

k8s内置了各种operator,但是这些operator更重视通用性,很难完全匹配实际工作需要,所以就需要对k8s进行二次开发,编写各种operator,这也是SRE工程师的必备技能之一

operator能单独管理应用集群,实现复杂操作;controllor:控制器,只能实现简单的容器操作

开发人员为k8s开发应用程序的时候,通常不会完整的部署一个分布式k8s集群,而是使用一个叫做MiniKube,它可以在单机上模拟出一个完整意义上的k8s集群

kubernetes的组件

资源池中的各个服务器叫做节点,运行Pod的节点叫做Worker Node(后文称Node

k8s组件分为三种:控制平面组件Node组件Addons

控制平面组件

控制平面(control plane)管理Node和Node上的Pods

控制平面组件可以分别运行在任意节点上,但是为了简单,通常会将所有控制平面组件运行在同一个节点上,还可以以副本的形式运行在多个节点上,然后禁止在这种节点上运行pod,这种节点就叫做Master Node(后文简称Master),当集群中只有一个Master时,就是单控制平面,有多个Master时,就是多控制平面,生产中肯定是多控制平面,但是学习中一般只使用单控制平面

kube-apiserver

https服务器,监听在6443端口,它将k8s集群内的一切都抽象成资源,提供RESTful风格的API,对资源进行增删改查等管理操作。

资源类型:Pod、Deployment、Service等等,反应在Etcd中,就是一张张的表

对象:资源表中的每一条数据项就是一个对象,例如 Pod表中的数据项就是Pod对象。所以资源表通常不叫Pod表、Deployment表…,而是叫做PodList、DeploymentList…

apiserver是整个k8s系统的总线,所有组件之间,都是通过它进行协同,它是唯一可以存储k8s集群的状态信息的组件(储存在Etcd)

生产中,apiserver需要做冗余,因为无状态,所以最少部署两个apiserver,因为是https服务器,所以需要做四层负载,使用Nginx、HAProxy、LVS均可,然后搭配keepalived给负载均衡做高可用

关于健康监测,分为AH(主动监测)和PH(被动监测或者叫异常值探测)

kube-controller-manager

控制器管理器,负责管理控制器,真正意义上让k8s所有功能得以实现的控制中心,k8s可以把运维人员日常重复性的工作代码化,而代码化集成的位置就在controller-manager中实现,controller-manager中有很多controller(deployment等数十种),这些controller才是真正意义上的k8s控制中心,可以将多controller打包起来,单一运行。

controller loop:控制循环

kube-scheduler

调度器,调度pod,它的核心作用就是运行应用,scheduler时刻关注着每个节点的资源可用量,以及运行pod所需的资源量,让二者达到最佳匹配,让pod以最好的状态运行

etcd

不是k8s内置,而是第三方的,基于raft协议,使用go研发的轻量级、分布式、支持数据强一致的kv存储系统,为避免脑裂,通常部署3个或5个节点

cloud-controller-manager

略…

Node组件

Node组件运行在所有的节点上,包括Master

kubelet

工作在每个Node上的agent(代理),与api server建立联系,监视api server中与自己node相关的pod的变动信息,执行指令操作

kube-porxy

守护进程,管理当前节点的iptables或ipvs规则,而且管理的只是和service相关的规则

监控service,把集群上的每一个service的定义转换为本地的ipvs或iptables规则

kube-proxy是运行在集群中的每个节点上的网络代理,实现了Kubernetes服务概念的一部分。
kube-proxy维护节点上的网络规则。这些网络规则允许从集群内部或外部的网络会话到Pods进行网络通信。
kube-proxy使用操作系统包过滤层(如果有的话)并且它是可用的。否则,kube-proxy将自己转发流量

Container runtime

通常是docker,其他类型的容器也支持

Addons

附加组件扩展了Kubernetes的功能

插件使用Kubernetes资源(DaemonSet, Deployment,等等)来实现集群特性。因为它们提供了集群级的特性,所以插件的命名空间资源属于kube-system命名空间。

DNS

CoreDNS,k8s中,DNS是至关重要的,所有的访问都不会基于ip,而是基于name,name再通过DNS解析成ip

Web UI

集群监控系统

prometheus

集群日志系统

EFK、LG

Ingress Controller

入栈流量控制器,是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP。

附件千千万,按需部署

kubectl

kubectl是kube-apiserver的命令行客户端,就像redis-cli是redis的命令行客户端

所以很显然,也可以使用python、go、php等编程语言操作kube-apiserver

创建对象的三种方式

  1. 命令式命令:命令,全部配置通过选项指定
  2. 命令式配置文件:命令,加载配置文件
  3. 声明式配置文件:声明式命令,加载配置清单

推荐使用第三种

配置清单:

1
2
3
4
5
6
7
8
9
10
11
12
# 配置清单的规范叫做资源规范,范例:
apiVersion: v1
kind: Pod
metadata:
name: myPod
labels:
app: mypod
release: canary
spec: # 期望状态
containers:
- name: demoapp
image: ikubernetes/demoapp:v1.0

资源清单是yml格式,api-server会自动转成json格式

如果实际状态和期望状态有出入,控制器的控制循环就会监控到差异,然后将需要做出的更改提交到apiserver,调度器scheduler监控到apiserver中有未执行的操作,就会去找适合执行操作的node,然后提交到apiserver,kubelet监控到apiserver中有关于自己节点的操作,就会执行操作,将执行结果返回给apiserver,apiserver再更新实际状态

部署(centos7)

kubeadm init

  1. run preflight checks:预检
  2. kubelet start:启动
  3. generate certificate:生成证书
  4. generate kubeconfig files:生成kubeconfig文件,/etc/kubernetes/*.conf
  5. generate static pod manifests for the control plane:生成静态pod的清单,/etc/kubernetes/manifests/*.yaml
  6. wait for the control plane to be healthy:等待pod启动成功
  7. Upload kubeadm & kubelet config to a ConfigMap
  8. Taint and label the master:给master节点设置污点,效果就是将来pod不会部署到master上
  9. Generate a (by default random) Bootstrap Token:生成一个引导令牌,节点凭令牌加入集群
  10. Setup the RBAC Authorization System:设置基于角色的授权模型
  11. Install DNS and Proxy Addons:安装附件

pod

pop是容器集,是k8s的最小运行单元,一个pop中的所有容器必须运行在同一node上

Kubernetes 集群中的 Pod 主要有两种用法:

  • 运行单个容器的 Pod。”每个 Pod 一个容器”模型是最常见的 Kubernetes 用例; 在这种情况下,可以将 Pod 看作单个容器的包装器,并且 Kubernetes 直接管理 Pod,而不是容器。
  • 运行多个协同工作的容器的 Pod。 Pod 可能封装由多个紧密耦合且需要共享资源的共处容器组成的应用程序。 这些位于同一位置的容器可能形成单个内聚的服务单元 —— 一个容器将文件从共享卷提供给公众, 而另一个单独的“挂斗”(sidecar)容器则刷新或更新这些文件。 Pod 将这些容器和存储资源打包为一个可管理的实体。

一个pod就像是一个虚拟机

pause是pod的基础设施容器,这个容器的作用是给pod内部容器提供可被加入和共享的net、ipc、uts namespace,同时我们向一个pod附加volume时,也是附加在pause之上,从而可以被共享给一个pod内的多个容器

建立pod

p83,4.5.2 pod的创建过程

通信

pod内的容器通信

复习:命名空间,linux底层概念,在内核层实现,容器使用namespce技术实现容器间相互隔离

  • mnt namespace:隔离根,即chroot技术
  • ipc namespace:隔离进程间通信
  • uts namespace:隔离系统信息,主机名等信息
  • pid namespace:隔离进程号
  • net namespace:隔离网络
  • user namespce:隔离用户

运行在同一个pod内的容器,共享net、ipc、uts、一组存储卷,亲密关系,同进同退

node内pod之间通信

借助于网络插件实现,通过bridge通信

跨node的pod之间通信

借助于网络插件实现,两种实现网络模型:叠加网络 和 承载网络

叠加:搭建隧道

承载:设置路由表

service

pod之间通信,一般不会pod直接访问pod,而是pod先访问service,然后service再到pod

kube-proxy会把集群上的每一个service的定义转换为本地的ipvs或iptables规则,所以当访问service ip(cluster ip)时,在内核中就会自动转向service后的某个pod的ip地址

service的ip也不会直接拿来用,而是访问service的name,使用CoreDNS将name解析为ip

service有三种实现模型:userspace、iptables、ipvs,ipvs性能最好,p138,6.1.2

service的ClusterIP是一个虚拟ip,它没有附着在任何的网络设备上,仅仅存在于iptables规则中,通过dnat实现访问clusterIP时的负载均衡。

service网段不能跟机房网络、docker网段、容器网段冲突,否则可能会导致网络不通。

service的clusterIP是k8s集群内的虚拟ip,不同的k8s集群可以使用相同的service网段,在k8s集群外是访问不通service的clusterIP的。

参考:https://www.cnblogs.com/fuyuteng/p/11598768.html

集群外部的客户端访问集群中的服务

两种方式:

  1. 集群外的流量先进入节点网络,再进入service网络,最后进入pod网络
  2. 物理桥接,让pod共享节点的网络名称空间

默认情况下,容器没有资源的使用限制,docker提供了控制容器使用资源的方法,可以限制容器使用多少内存或 CPU等, 在docker run 命令的运行时配置标志实现资源限制功能。

容器的内存限制

为了运行效率,建议关闭交换内存,如果内存不够了,打报告采购就好了,而且k8s也禁止使用交换内存

在容器中使用free命令,看到的是宿主机的内存情况

内存相关配置项 说明
-m | –mermory= 容器可以使用的最大内存,硬限制,最小4m,此项常用
–mermory-swap 交换内存相关的配置项,如果宿主机关闭了交换内存,建议忽略此项

范例:

1
2
3
# 单位:b、k、m、g
# 限制容器的内存不超过300m
root@u3:~# docker container run -it -m 300m harbor.ljk.org/library/alpine:v1

容器的CPU限制

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

公有云仓库分为 官方 和 阿里云等第三方仓库,推荐第三方

私有云仓库一般通过 docker registory 或者 docker harbor这两个软件搭建,推荐docker harbor

阿里云docker仓库

  1. 访问凭证
  2. 命名空间
  3. 镜像仓库

范例:

1
2
3
4
5
6
7
8
9
10
# 1. 浏览器的登录阿里云,创建命名空间107,镜像仓库可以创建也可以不创建,如果不创建,push的时候会自动创建
# 2. 登录阿里云,交互式,密码存储在~/.docker/config.json
docker login --username=1076956365@qq.com registry.cn-beijing.aliyuncs.com
# 3. 给镜像打标签,注意格式
docker tag nginx-alpine:v1 registry.cn-beijing.aliyuncs.com/107/nginx:1.18-v1
# 4. 上传到阿里云的docker镜像仓库
docker push registry.cn-beijing.aliyuncs.com/107/nginx:1.18-v1
# 5. 刷新网站页面,如果没有看到镜像,可能是区域设置不对
# 6. 其他机器下载镜像
docker pull registry.cn-beijing.aliyuncs.com/107/nginx:1.18-v1

docker之分布式仓库 harbor

harbor功能介绍:

  • 基于角色的访问控制
  • 镜像复制
  • 图形化用户界面
  • 审计管理
  • 国际化
  • resful api
  • 部署简单

harbor组成:

harbor是由很多容器组成实现完整功能

  • proxy:对应启动组件nginx。它是一个nginx反向代理,代理notary client(镜像认证)、docker client(镜像上传下载等)和浏览器的访问请求(core service)给后端的各服务
  • UI(Core Service):对应启动组件harbor-ui。底层数据存储使用mysql数据库,主要提供了四个子功能:
    • UI:一个web管理页面ui
    • API:Harbor暴露的API服务
    • Auth:用户认证服务,decode后的token中的用户信息在这里进行认证;auth后端可以接db、ldap、uaa三种认证实现
    • Token服务(上图中未体现):负责根据用户在每个project中的role来为每一个docker push/pull命令发布一个token,如果从docker client发送给registry的请求没有带token,registry会重定向请求到token服务创建token
  • registry:对应启动组件registry。负责存储镜像文件,和处理镜像的pull/push命令。Harbor对镜像进行强制的访问控制,Registry会将客户端的每个pull、push请求转发到token服务来获取有效的token
  • admin service:对应启动组件harbor-adminserver。是系统的配置管理中心附带检查存储用量,ui和jobserver启动时候需要加载adminserver的配置
  • job service:对应启动组件harbor-jobservice。负责镜像复制工作的,他和registry通信,从一个registry pull镜像然后push到另一个registry,并记录job_log
  • log collector:对应启动组件harbor-log。日志汇总组件,通过docker的log-driver把日志汇总到一起
  • db:对应启动组件harbor-db,负责存储project、 user、 role、replication、image_scan、access等的metadata数据

配置harbor仓库

两台harbor服务器 10.0.0.118 和 10.0.0.119 均按照以下步骤配置:

  1. 安装docker
  2. 安装docker compose,docker compose 必须先于harbor安装,否则会报错
  3. 下载Harbor安装包并解压缩
  4. 编辑配置文件 harbor.yml,旧版本是harbor.cfg
  5. 运行 harbor 安装脚本
  6. 实现开机自动启动 harbor
  7. 登录 harbor 主机网站
  8. 建立项目
  9. 修改harbor配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1. 安装docker
$ sudo apt-get update
$ sudo apt-get -y install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
$ curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository \
"deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \
$(lsb_release -cs) \
stable"
$ sudo apt-get update
$ sudo apt -y install docker-ce

# 以上是直接安装最新版本,推荐安装时指定版本
$ apt-cache madison docker-ce
$ sudo apt -y install docker-ce=<VERSION_STRING>
1
2
3
4
5
# 2. 安装docker compose
root@u1:~# apt -y install python3-pip # 为了方便,直接安装pip
root@u1:~# pip3 install docker-compose
root@u1:~# docker-compose --version
docker-compose version 1.27.4, build unknown
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 3. 下载Harbor安装包并解压缩
# 可以下载在线安装包或者完整的离线安装包,推荐下载离线包
# 下载网址:https://github.com/goharbor/harbor/releases
# 推荐使用迅雷下载:harbor-offline-installer-v1.10.6.tgz
root@u1:/usr/local/src# tar zxvf harbor-offline-installer-v1.10.6.tgz
root@u1:/usr/local/src# cd harbor/
root@u1:/usr/local/src/harbor# ll
total 700264
drwxr-xr-x 2 root root 4096 Nov 24 13:29 ./
drwxr-xr-x 3 root root 4096 Nov 24 13:29 ../
-rw-r--r-- 1 root root 3398 Nov 17 03:58 common.sh
-rw-r--r-- 1 root root 717021676 Nov 17 03:59 harbor.v1.10.6.tar.gz
-rw-r--r-- 1 root root 5882 Nov 17 03:58 harbor.yml
-rwxr-xr-x 1 root root 2284 Nov 17 03:58 install.sh*
-rw-r--r-- 1 root root 11347 Nov 17 03:58 LICENSE
-rwxr-xr-x 1 root root 1749 Nov 17 03:58 prepare*
1
2
3
4
5
6
7
8
9
10
11
12
13
# 4. 编辑配置文件 harbor.yml
root@u1:/usr/local/src/harbor# vim harbor.yml
#只需要修改下面两行
hostname: 10.0.0.118 # 修改此行,指向当前主机IP 或 FQDN
harbor_admin_password: 123456 # 修改此行指定harbor登录用户admin的密码

# 不需要https,注释以下内容
# https:
# # https port for harbor, default is 443
# port: 443
# # The path of cert and key files for nginx
# certificate: /your/certificate/path
# private_key: /your/private/key/path
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 5. 运行 harbor 安装脚本
root@u1:/usr/local/src# mv harbor /usr/local/
root@u1:/usr/local/src# cd /usr/local/harbor/
root@u1:/usr/local/src# ./prepare
...
root@u1:/usr/local/src# ./install.sh
...
Creating network "harbor_harbor" with the default driver
Creating harbor-log ... done
Creating harbor-db ... done
Creating redis ... done
Creating registry ... done
Creating registryctl ... done
Creating harbor-portal ... done
Creating harbor-core ... done
Creating harbor-jobservice ... done
Creating nginx ... done
✔ ----Harbor has been installed and started successfully.----
root@u1:/usr/local/src# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
goharbor/chartmuseum-photon v1.10.6 01b70eccaf71 7 days ago 178MB
goharbor/harbor-migrator v1.10.6 a5d4a4ee44e4 7 days ago 356MB
goharbor/redis-photon v1.10.6 99e25b65195c 7 days ago 132MB
goharbor/clair-adapter-photon v1.10.6 aa72598ecc12 7 days ago 61.3MB
goharbor/clair-photon v1.10.6 da1b03030e34 7 days ago 171MB
goharbor/notary-server-photon v1.10.6 37c8bed3e255 7 days ago 142MB
goharbor/notary-signer-photon v1.10.6 c56d82220929 7 days ago 139MB
goharbor/harbor-registryctl v1.10.6 1d3986d90c65 7 days ago 101MB
goharbor/registry-photon v1.10.6 3e669c8204ed 7 days ago 83.7MB
goharbor/nginx-photon v1.10.6 a39d8dd46060 7 days ago 43.7MB
goharbor/harbor-log v1.10.6 1085d3865a57 7 days ago 106MB
goharbor/harbor-jobservice v1.10.6 aa05538acecf 7 days ago 143MB
goharbor/harbor-core v1.10.6 193e76e6be5d 7 days ago 129MB
goharbor/harbor-portal v1.10.6 942a9c448850 7 days ago 51.8MB
goharbor/harbor-db v1.10.6 37da2e5414ae 7 days ago 170MB
goharbor/prepare v1.10.6 35f073e33ec5 7 days ago 177MB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 6. 实现开机自动启动 harbor
root@u1:~# vim /lib/systemd/system/harbor.service
[Unit]
Description=Harbor
After=docker.service systemd-networkd.service systemd-resolved.service
Requires=docker.service
Documentation=http://github.com/vmware/harbor

[Service]
Type=simple
Restart=on-failure
RestartSec=5
ExecStart=/usr/local/bin/docker-compose -f usr/local/harbor/docker-compose.yml up
ExecStop=/usr/local/bin/docker-compose -f usr/local/harbor/docker-compose.yml down

[Install]
WantedBy=multi-user.target

root@u1:~# systemctl daemon-reload
root@u1:~# systemctl enable --now harbor.service
Created symlink /etc/systemd/system/multi-user.target.wants/harbor.service → /lib/systemd/system/harbor.service.
  1. 登录 harbor 主机网站 http://10.0.0.118

1
2
3
4
5
6
# 9. 修改harbor配置
# 后期如果需要修改harbor配置
1.修改 harbor.yml 文件
2.停止harbor: systemctl stop harbor.service
3.执行prepare
4.启动harbor:sysytemcrl start harbor.service

配置docker客户端

客户端 10.0.0.117

  1. 安装docker
  2. 登录harbor
  3. 给本地镜像大标签并上传到harbor
  4. 下载harbor的镜像
1
2
# 1. 安装docker
略...
  1. 建立项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 3. 登录harbor.两种方法,命令行或者配置文件
# 方法一:命令行
root@u3:~# vim /usr/lib/systemd/system/docker.service
...
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --insecure-registry 10.0.0.118 --insecure-registry 10.0.0.119
...
# 方法二:配置文件,推荐
root@u3:~# vim /etc/docker/daemon.json
{
"registry-mirrors": ["https://3417nt4m.mirror.aliyuncs.com"],
"insecure-registries": ["10.0.0.118", "10.0.0.119"]
}
root@u3:~# systemctl restart docker.service
root@u3:~# docker login 10.0.0.118
Username: admin
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
1
2
3
4
5
# 3. 给本地镜像大标签并上传到harbor
# 修改 images 的名称,不修改成指定格式无法将镜像上传到 harbor 仓库
# 格式:Harbor主机IP/项目名/image名字:版本
root@u3:~# docker tag alpine:latest 10.0.0.118/library/alpine-base:3.12
root@u3:~# docker push 10.0.0.118/library/alpine-base:3.12
1
2
3
# 4. 下载harbor的镜像
# 另开一台机器,安装docker,daemon.json设置insecure-registries,就可以直接下载镜像
root@u4:~# docker image pull 10.0.0.118/library/alpine-base:3.12

harbor高可用

实现harbor有两种方式:共享存储 和 镜像复制,这里只学习后者,可以通过web界面直接配置镜像复制

前面配置了两台harbor仓库,10.0.0.118 和 10.0.0.119,但是只使用了一台,这里使用另一台组成双向复制

注意:不是主从,而是双向复制,通过负载均衡器将请求分流

h1:10.0.0.118
h2:10.0.0.119

  1. 确保 h1 和 h2 中有相同的项目

  2. h1 和 h2 均新建仓库,目标分别为对方

    复制模式选择 push-based

  3. h1 和 h2 均新建复制,目标分别为对方

  4. 测试,分别在h1和h2上传(注意上传前先登录harbor)然后删除,都能同步成功

harbor配置https

harbor默认使用http,可以配置https,不过我认为没有这个必要

在前面配置好harbor仓库的基础上,执行以下操作:

  1. 配置服务端

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    root@u1:~# mkdir -p /root/.rnd
    root@u1:~# mkdir -p /usr/local/harbor/certs
    root@u1:~# cd /usr/local/harbor/certs
    root@u1:/usr/local/harbor/certs# ls
    # 创建私有CA
    root@u1:/usr/local/harbor/certs# openssl req -newkey rsa:1024 -nodes -sha256 -keyout ca.key -x509 -subj "/CN=ca.ljk.org" -days 3650 -out ca.crt
    Generating a RSA private key
    ..............+++++
    ...................................+++++
    writing new private key to 'ca.key'
    -----
    root@u1:/usr/local/harbor/certs# ls
    ca.crt ca.key
    # 生成harbor主机的证书申请
    root@u1:/usr/local/harbor/certs# openssl req -newkey rsa:1024 -nodes -sha256 -subj "/CN=harbor.ljk.org" -keyout harbor.ljk.org.key -out harbor.ljk.org.csr
    Generating a RSA private key
    .....................................................................+++++
    ..........+++++
    writing new private key to 'harbor.ljk.org.key'
    -----
    root@u1:/usr/local/harbor/certs# ls
    ca.crt ca.key harbor.ljk.org.csr harbor.ljk.org.key
    # 给harbor主机颁发证书
    root@u1:/usr/local/harbor/certs# openssl x509 -req -in harbor.ljk.org.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out harbor.ljk.org.crt
    Signature ok
    subject=CN = harbor.ljk.org
    Getting CA Private Key
    root@u1:/usr/local/harbor/certs# tree
    .
    ├── ca.crt
    ├── ca.key
    ├── ca.srl
    ├── harbor.ljk.org.crt
    ├── harbor.ljk.org.csr
    └── harbor.ljk.org.key

    0 directories, 6 files
    root@u1:/usr/local/harbor/certs# vim ../harbor.yml
    hostname: harbor.ljk.org # 此行需改为域名
    https:
    # https port for harbor, default is 443
    port: 443
    # The path of cert and key files for nginx
    certificate: /usr/local/harbor/certs/harbor.ljk.org.crt
    private_key: /usr/local/harbor/certs/harbor.ljk.org.key
    ...
    root@u1:/usr/local/harbor/certs# cd ..
    root@u1:/usr/local/harbor# systemctl stop harbor.service # 这一步要等挺久
    root@u1:/usr/local/harbor# ./prepare
    root@u1:/usr/local/harbor# ./install.sh
    root@u1:/usr/local/harbor# systemctl start harbor.service

    访问:https://10.0.0.118

  2. 配置客户端

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    root@u3:~# echo '10.0.0.118 harbor.ljk.org' >> /etc/hosts

    # 因为是自建证书,所以harbor规定,客户端也下载一份,位于/etc/docker/certs.d/harbor.ljk.org
    # 其实,只需要harbor.ljk.org.crt即可,这里为了方便,全部拷贝过来
    root@u3:~# scp lujinkai@harbor.ljk.org:/usr/local/harbor/certs/* /etc/docker/certs.d/harbor.ljk.org/

    # 登录成功
    root@u3:~# docker login harbor.ljk.org

    # 上传镜像
    root@u3:~# docker image push harbor.ljk.org/library/alpine:v1

docker 网络支持5种网络模式:none、bridge、host、container、network-net

创建新容器时,docker run命令可以指定网络模式:

1
2
3
4
5
6
7
8
docker run --network <mode>

# mode:默认是bridge
none
bridge
host
container:容器名或容器ID
自定义网络名称

bridge 模式

默认模式,容器连接到一个虚拟网桥与外界通信,通过SNAT访问外网,通过DNAT可以让容器被外部主机访问,所以此模式也称为NAT模式

此模式会启动宿主机的ip_forward功能

bridge模式特点:

  • 网络资源隔离:不同主机的容器之间无法直接通信
  • 因为NAT转换,所以性能较低
  • 端口管理繁琐,每个容器必须手动指定唯一的端口,容易产生端口冲突

修改默认的bridge模式网络配置:

方法一:修改docker.service

1
2
3
4
5
# docker0默认ip为172.17.0.1/16,修改为10.100.0.1/24
root@Z510:~# vim /usr/lib/systemd/system/docker.service
...
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=10.100.0.1/24
...

方法二:修改daemon.json,推荐这种方法

1
2
3
4
5
6
7
8
9
10
root@Z510:~# vim /etc/docker/daemon.json
# hosts 指定docker守护进程侦听的地址,默认/var/run/docker.sock
"hosts": ["tcp://0.0.0.0:2375", "fd://"],
"bip": "192.168.100.100/24", # docker0网卡的IP
"fixed-cidr": "192.168.100.128/26", # 分配给容器的IP范围
"fixed-cidr-v6": "2001:db8::/64",
"mtu": 1500,
"default-gateway": "192.168.100.200", # 网关必须和bip在同一个网段
"default-gateway-v6": "2001:db8:abcd::89",
"dns": [ "1.1.1.1", "8.8.8.8"]

host 模式

容器和宿主机之间网络不隔离(其他资源隔离),容器不创建自己的虚拟网卡,而是使用宿主机的网卡和IP地址,因此在容器里面查看到的IP信息就是宿主机的信息,访问容器的时候直接使用宿主机IP+容器端口即可

此模式由于直接使用宿主机的网络无需转换,网络性能最高,但是各容器内使用的端口不能相同,适用于运行容器端口比较固定的业务

host 网络模式特点:

  • 共享宿主机网络
  • 网络性能无损耗
  • 网络故障排除相对简单
  • 各容器网络无隔离
  • 网络资源无法分别统计
  • 端口管理困难: 容易产生端口冲突
  • 不支持端口映射

范例:

1
docker run -d --network host --name web1 nginx-centos7-base:1.6.1

none 模式

容器不会进行任何网络配置,没有网卡、没有IP也没有路由,因此默认无法与外界通信,需要手动添加网卡配置IP等,所以极少使用

containter 模式

指定一个已经存在的容器(选择与其通信频繁的容器),共享其网络,因此这个容器的端口不能和被指定容器的端口冲突

这种模式也较少使用

自定义网络模式

1
2
3
4
5
6
7
8
9
10
11
# docker network --help
Usage: docker network COMMAND

Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks

自定义网络内的容器可以直接通过容器进行相互的访问

可以使用自定义网络模式,实现不同集群应用的独立网络管理,而互补影响,而且在一个网络内,可以直接利用容器名称相互访问,非常便利

创建自定义网络:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# docker network create --help
Usage: docker network create [OPTIONS] NETWORK

Options:
--attachable Enable manual container attachment
--aux-address map Auxiliary IPv4 or IPv6 addresses used by Network driver (default map[])
--config-from string The network from which copying the configuration
--config-only Create a configuration only network
-d, --driver string Driver to manage the Network (default "bridge")
--gateway strings IPv4 or IPv6 Gateway for the master subnet
--ingress Create swarm routing-mesh network
--internal Restrict external access to the network
--ip-range strings Allocate container ip from a sub-range
--ipam-driver string IP Address Management Driver (default "default")
--ipam-opt map Set IPAM driver specific options (default map[])
--ipv6 Enable IPv6 networking
--label list Set metadata on a network
-o, --opt map Set driver specific options (default map[])
--scope string Control the network's scope
--subnet strings Subnet in CIDR format that represents a network segment
1
2
3
docker network create -d <mode> --subnet <CIDR> --gateway <网关> <自定义网络名称>

#注意mode不支持host和none

容器间通信

禁止同宿主机的不同容器间通信

docker.service

1
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --icc=false

daemon.json

1
"icc": false

容器名称互联

前文中,自定义网络模式,可以实现容器名称互联,如果是默认模式,想要实现这个功能,需要在创建容器时,使用–link选项

范例:实现a1和a2容器名称互联

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 1. 创建容器a1
root@Z510:~# docker container run -it --name a1 alpine:latest
/ # hostname -i
172.17.0.2
# 2. 创建容器a2
root@Z510:~# docker container run -it --name a2 --link a1 alpine:latest
/ # hostname -i
172.17.0.3
/ # cat /etc/hosts
...
172.17.0.2 a1 6079167b0ed1
172.17.0.3 b4e8abef6893
/ # ping a1 # a2可以ping通a1
PING a1 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.191 ms
...
# 3. 修改容器a1的hosts
/ # vi /etc/hosts
# 添加如下行
172.17.0.3 a2 b4e8abef6893
/ # ping a2 # a1可以ping通a2
PING a2 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.135 ms
...

同宿主机之间不同网络的容器通信

同一个宿主机,创建两个容器,一个使用自定义网络,一个使用默认的bridge模式,默认这两个容器是无法通信的,如果想要实现通信,有两种方式:修改iptables规则 和 通过docker network connect实现

本笔记只记录第二种方式:

1
2
3
4
5
6
7
8
9
10
# docker network connect --help
Usage: docker network connect [OPTIONS] NETWORK CONTAINER

Options:
--alias strings Add network-scoped alias for the container
--driver-opt strings driver options for the network
--ip string IPv4 address (e.g., 172.30.100.104)
--ip6 string IPv6 address (e.g., 2001:db8::33)
--link list Add link to another container
--link-local-ip strings Add a link-local address for the container

范例:默认docker0中的容器为test1,自定义网络test-net中的容器为test2

1
2
3
4
5
6
7
# 1. 创建网络和容器,过程略...
# 2. 让默认网络中容器test1可以连通自定义网络test-net的容器test2
docker network connect test-net test1
ip a # 可以看到新增一个网卡,ip和test-net同网段
# 3. 让自定义网络中容器test2可以连通默认网络的容器test1
docker network connect bridge test2
ip a # 可以看到新增一个网卡,ip和docker0同网段

docker容器创建后,必不可少的要和其它主机或容器进行网络通信

docker的网络模式和KVM很相似

docker 网络连接模式

跨宿主机的容器之间网络通信

四种方法:

  1. 桥接
  2. NAT
  3. Open vSwitch
  4. weave

生产中,以上四种都不用,而是通过k8s实现,如果真的用到了,再回来复习课件

案例:docker & LVS 实现网络架构高可用

整体规划图:

过程略..

docker镜像由多个只读层叠加而成,启动容器时,docker会加载只读镜像层并在镜像栈顶部添加一个读写层

所有的修改都被复制到读写层,保存在diff目录,原理就是“写时复制(COW)”

但是一旦删除容器,读写层也会被删除,所以为了数据持久化,需要将容器中的数据保存到宿主机的制定目录,方法就是使用数据卷(Data Volume):直接将宿主机目录挂载到容器的指定目录

数据卷

数据卷实际上就是宿主机上的目录或文件,可以直接mount到容器中使用

实际生产环境中,需要针对不同类型的服务,不同类型的数据存储要求做到相应的规划,最终保证服务的可扩展性、稳定性以及数据的安全性

使用场景:数据库、日志、静态web页面、应用配置文件、多容器间目录或文件共享

数据卷特点:

  • 可以多容器之间共享
  • 依赖宿主机目录,宿主机出问题,依赖的容器就会受影响,当宿主机较多时,不方便统一管理
  • 镜像中的挂载点中包含数据,则在容器初始化时会将数据拷贝到数据卷(匿名和命名)中

数据卷的使用

1
2
3
4
5
docker container run -v [host-src:]container-dest[:<options>]

options:
ro:容器内对此数据卷只读,代码等文件适合设置为只读
rw:容器内对此数据卷读写,默认
1
2
3
4
5
6
7
8
# 将宿主机目录挂载容器目录,两个目录都可自动创建
-v <宿主机绝对路径的目录或文件>:<容器目录或文件>[:ro]

# 匿名卷,宿主机自动生成/var/lib/docker/volumes/<卷ID>/_data目录,并挂载至容器指定路径
-v <容器内路径>

# 命名卷,宿主机自动生成/var/lib/docker/volumes/<卷名>/_data目录,并挂载至容器指定路径
-v <卷名>:<容器目录路径>

管理卷命令:

1
2
3
4
5
6
7
8
9
# docker volume --help
Usage: docker volume COMMAND

Commands:
create Create a volume
inspect Display detailed information on one or more volumes
ls List volumes
prune Remove all unused local volumes
rm Remove one or more volumes

关于匿名卷和命名卷:

命名卷,因为有名字可以指定,在用过一次后,以后挂载容器的时候还可以使用,所以一般需要保存的数据使用命名卷保存。

匿名卷没有名字,随容器建立而建立,当容器消亡,匿名卷即使还存在,但也失去了意义,因此匿名卷只存放无关紧要的临时数据。

Dockerfile中指定VOLUME为匿名数据卷,其目的只是为了将某个路径确定为卷。

数据卷默认可能会保存于 /var/lib/docker/volumes,不过一般不需要、也不应该访问这个位置。

按照最佳实践的要求,不应该在容器存储层内进行数据写入操作,所有写入应该使用卷。

1
2
3
4
# 查看数据卷的挂载关系
docker inspect --format="{{.Mounts}}" <容器ID>
# 删除所有数据卷
docker volume rm `docker volume ls -q`

案例

MySQL使用数据卷:

1
2
3
4
5
docker run -d \
--name mysql \
-p 3306:3306 \
-v /data/mysql/:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 mysql:5.7.30

文件数据卷:

1
2
3
4
5
docker run -d \
-v /data/bin/catalina.sh:/apps/tomcat/bin/catalina.sh:ro \
-v /data/testapp:/data/tomcat/webapps/testapp \
-v /data/logs:/apps/tomcat/logs \
-p 8080:8080 tomcat-web:app1

docker 镜像生命周期

制作镜像方法:

  • 手工制作(基于容器)
  • 自动制作(基于dockerfile),企业通常都是基于dockerfile制作镜像

手动构建镜像

将现有容器通过 docker commitdocker container commit 手动构建镜像

根据容器的更改创建新镜像:

1
2
3
4
5
6
7
8
# docker container commit --help
Usage: docker container commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

Options:
-a, --author string 作者 (e.g., "John Hannibal Smith <hannibal@a-team.com>")
-c, --change list 使用Dockerfile指令来创建镜像
-m, --message string 提交时的说明文字
-p, --pause 在commit时,将容器暂停 (default true)

说明:

  • 制作镜像和容器的状态无关,停止状态也可以制作
  • 如果没有指定[REPOSITORY[:TAG]],REPOSITORY和TAG都为<none>
  • 提交的时候标记TAG,后期可以根据TAG标记创建不同版本的镜像以及创建不同版本的容器

具体步骤

  1. 下载一个官方的基础镜像,例如:centos、ubuntu、alpine
  2. 基于基础镜像启动一个容器,并进入
  3. 在容器里面进行安装服务、修改配置等操作
  4. 提交一个新镜像 docker container commit
  5. 基于自己的镜像创建容器并访问、

案例:基于alpine基础镜像制作nginx镜像

  1. 下载最新版alpine基础镜像

    1
    root@Z510:~# docker pull alpine
  2. 启动alpine并进入

    1
    2
    root@Z510:~# docker container run -it alpine
    / #
  3. 另开一个终端,将shell脚本拷贝到alpine镜像

    1
    2
    3
    4
    5
    lujinkai@Z510:~/www/script$ sudo docker container ls
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    b8de1bdb6c88 alpine "/bin/sh" About a minute ago Up About a minute funny_chatelet

    lujinkai@Z510:~/www/script$ sudo docker container cp -a ./alpine-docker/ b8de:/root
  4. 回到容器,运行shell脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    root@Z510:~# docker container run -it alpine
    / # cd
    ~ # ls
    alpine-docker
    ~ # cd alpine-docker/
    ~/alpine-docker # ./install.sh
    ....
    make[1]: Leaving directory '/root/alpine-docker/src/nginx-1.18.0'
    Nginx installed successfully!
    ~/alpine-docker # exit
  5. 提交镜像

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    lujinkai@Z510:~$ sudo docker container commit \
    -a 'lujinkai<root@lujinkai.com>' \
    -c 'EXPOSE 80' \
    -c 'CMD ["/usr/local/nginx/sbin/nginx"]' \
    b8de1bdb6c88 nginx-alpine:v1
    lujinkai@Z510:~$ sudo !!
    sudo docker image ls
    REPOSITORY TAG IMAGE ID CREATED SIZE
    nginx-alpine v1 de56d80c5c8c 14 seconds ago 340MB
    alpine latest d6e46aa2470d 4 weeks ago 5.57MB
  6. 启动基于新制作镜像的容器

    1
    2
    3
    4
    root@Z510:~# docker container run -d -p 80:80 nginx-alpine:v1 
    ebbe778a7fe303e6a5cb840203d95a7b5e2a07208365b71f784ddc8357a664d7
    root@Z510:~# curl 127.0.0.1:81
    hello nginx

  7. iptables

    1
    2
    3
    4
    5
    6
    root@Z510:~# iptables -t nat -nL
    ...
    Chain DOCKER (2 references)
    target prot opt source destination
    RETURN all -- anywhere anywhere
    DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:81 to:172.17.0.2:80
  8. ss

    1
    2
    3
    4
    5
    root@Z510:~# ss -ntl
    State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
    ...
    LISTEN 0 4096 *:81 *:*
    ...
  9. 有需求的话,可以导出镜像:docker image save [OPTIONS] IMAGE

自动构建镜像

利用 DockerFile 文件执行 docker build 自动构建镜像

个人觉得还是手动的比较方便,然后在容器内无法完成的设置,docker container commit提交的时候设置-c参数即可

Dockerfile 相关指令

  • FROM
  • LABEL
  • RUN
  • ENV
  • COPY
  • ADD
  • CMD
  • ENTRYPOINT
  • ARG
  • VOLUME
  • EXPOSE
  • WORKDIR
  • ONBUILD
  • USER
  • HEALTHCHECK
  • STOPSIGNAL
  • SHELL

容器生命周期

容器管理docker container

启动容器 run

每次run,都会启动一个新的容器

1
2
# docker run [选项] [镜像名] [shell命令] [参数]
docker container run [OPTIONS] IMAGE [COMMAND] [ARG...]

COMMAND:一次性运行容器中命令

OPTIONS:

  • -i:Keep STDIN open even if not attached,通常和-t一起使用
  • -t:分配pseudo-TTY,通常和-i一起使用,注意对应的容器必须运行shell才支持进入
  • -d:后台运行容器,并返回容器ID,默认前台运行
  • –name string:启动容器时会自动随机字符作为容器名,–name指定容器名称
  • -h string:设置虚拟机内的hostname
  • –rm:退出后立即删除容器,一次性运行,用于测试
  • -p(小写) list:暴露指定端口映射,为避免宿主机端口冲突,要做好端口规划
  • -P(大写):暴露所有端口,随机,默认从32768开始
  • port:查看端口映
  • –dns list:Set custom DNS servers
  • –entrypoint string:Overwrite the default ENTRYPOINT of the image
  • –restart policy:
  • –privileged:赋予虚拟机内的root真正的root权限,有权限宿主机,没有特殊需求不要使用
  • -e=[]:传递环境变量
  • –env-file=[]:传递环境变量,文件
  • –restart string:容器的重启策略,面向生产环境的启动策略
    • no:默认策略,容器退出时不重启容器
    • on-failure:容器非正常退出时(退出状态非0),才会重启容器
    • on-failure:3:容器非正常退出时重启容器,最多重启3次
    • always:容器退出时总是重启容器,设置为always,则启动docker服务的时候会自动启动容器
    • unless-stopped:容器退出时总是重启容器,但是不考虑在docker守护进程启动时就已经停止了的容器

注意:容器启动后,如果容器内没有前台运行的进程,将自动退出停止

退出容器:exit 容器停止;ctrl+p+q 容器不停止

查看容器信息 ls、top、stats、inspect

  • 查看当前存在的容器
1
2
3
4
5
6
7
8
9
10
docker ps [OPTIONS]
docker container ls [OPTIONS]

选项:
-a, --all 查看所所有容器,包括退出状态的容器(默认只显示处于运行状态的容器)
-q, --quiet Only display numeric IDs
-s, --size 显示容器大小
-f, --filter 过滤,例如 `-f status=exited`
-l, --latest 显示最新创建的容器
-n, --last int Show n last created containers (includes all states)(default -1)
  • 查看容器内的进程
1
docker container top CONTAINER [ps OPTIONS]
  • 查看容器资源使用情况
1
2
3
4
5
6
7
8
# docker container stats --help
Usage: docker container stats [OPTIONS] [CONTAINER...]

Options:
-a, --all Show all containers (default shows just running)
--format string Pretty-print images using a Go template
--no-stream Disable streaming stats and only pull the first result
--no-trunc Do not truncate output
  • 查看容器的详细信息
1
2
3
4
5
6
# docker container inspect --help
Usage: docker container inspect [OPTIONS] CONTAINER [CONTAINER...]

Options:
-f, --format string Format the output using the given Go template
-s, --size Display total file sizes

范例:

1
2
3
docker inspect 9997
docker inspect -f "{{.Metadata}}" test:v1.0 # 选择性查看
docker inspect -f "{{.Created}}" c1

删除容器 rm

rm 删除容器,即使处于运行状态也被强制删除

prune 删除容器,只删除停止的容器

1
2
3
4
5
6
7
# docker container rm --help
Usage: docker container rm [OPTIONS] CONTAINER [CONTAINER...]

Options:
-f, --force Force the removal of a running container (uses SIGKILL)
-l, --link Remove the specified link
-v, --volumes 同时删除数据卷
1
2
3
4
5
6
# docker container prune --help
Usage: docker container prune [OPTIONS]

Options:
--filter filter Provide filter values (e.g. 'until=<timestamp>')
-f, --force 不提示确认信息

范例:删除指定状态的容器

1
docker rm `docker ps -qf status=exited`
1
alias rmc='docker container ls -aq | xargs -n1 docker container rm -f'

容器的启动和停止

1
docker start|stop|restart|pause|unpause 容器ID
  • start:启动容器,后台启动,并执行默认COMMAND
  • stop:关闭容器
  • restart:重启容器
  • pause:暂停容器中的所有进程
  • unpause:恢复容器中的进程

给正在运行的容器发信号 kill

默认信号 SIGKILL,即9信号

1
2
3
4
5
# docker container kill --help
Usage: docker container kill [OPTIONS] CONTAINER [CONTAINER...]

Options:
-s, --signal string Signal to send to the container (default "KILL")

进入正在运行的容器 exec

run -it 是新建容器,并进入,如果要进入正在运行的容器,推荐使用exec,此外 attach 也可以,但是不推荐

exec 的作用是在运行的容器中执行命令

1
2
3
4
5
6
7
8
9
10
11
12
# docker container exec --help
Usage: docker container exec [OPTIONS] CONTAINER COMMAND [ARG...]

Options:
-d, --detach Detached mode: run command in the background
--detach-keys string Override the key sequence for detaching a container
-e, --env list Set environment variables
-i, --interactive Keep STDIN open even if not attached
--privileged Give extended privileges to the command
-t, --tty Allocate a pseudo-TTY
-u, --user string Username or UID (format: <name|uid>[:<group|gid>])
-w, --workdir string Working directory inside the containe

常见用法:

1
2
#常见用法
docker exec -it 容器ID sh|bash # 进入容器,且exit退出但容器不停止

暴露端口

端口映射的本质就是利用NAT技术实现的

暴露所有端口,随机:大写P

1
docker container run -P

暴露指定端口:小写p

1
2
3
4
5
6
7
8
9
10
docker container run -p 

# 范例
docker run -p 80 --name nginx-test-port1 nginx # 容器80映射到宿主机随机端口
docker run -p 81:80 --name nginx-test-port2 nginx # 容器80端口映射到宿主机本地端口81
docker run -p 10.0.0.100:82:80 --name nginx-test-port3 docker.io/nginx # 指定宿主机ip
docker run -p 10.0.0.100::80 --name nginx-test-port4 docker.io/nginx
docker run -p 10.0.0.100:83:80/udp --name nginx-test-port5 docker.io/nginx #指定udp,默认tcp
# 一次性映射多个端口+协议
docker run -p 8080:80/tcp -p 8443:443/tcp -p 53:53/udp --name nginx-test-port6 nginx

查看容器日志 logs

查看容器中运行的进程在控制台输出的日志信息,如果容器中的进程不在控制台输出日志,那就没办法了,所以这种方法一般不用

1
2
3
4
5
6
7
8
9
10
# docker container logs --help
Usage: docker container logs [OPTIONS] CONTAINER

Options:
--details Show extra details provided to logs
-f, --follow Follow log output
--since string Show logs since timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)
--tail string Number of lines to show from the end of the logs (default "all")
-t, --timestamps Show timestamps
--until string Show logs before a timestamp (e.g. 2013-01-02T13:23:37) or relative (e.g. 42m for 42 minutes)

传递运行命令

docker run xxx启动容器,如果xxx容器中没有常驻前台的进程,xxx会认为没什么任务,在启动后马上退出,有的服务支持前台运行,有的不支持,如果服务不支持前台运行,我们可以启动一个常驻前台的进程,阻止容器推出,常用的方式是让容器运行tail -f /etc/hosts命令,注意不要监听频繁更改的文件,避免产生不必要的磁盘IO

范例:

1
2
3
4
5
6
# nginx前台运行,直接后台启动即可
docker container run -d nginx:1120
# alpine没有常驻前台的进程,以下两种方式均可
# 在容器内执行`/bin/sh`,然后把容器放到宿主机后台,sh是交互式命令,所以也有常驻前台的效果
docker container run -itd alpine
docker run -d alpine 'tail -f /etc/hosts'

指定容器DNS

默认采用宿主机的dns地址,可以在run启动容器时指定

范例:

1
2
3
4
5
root@Z510:~# docker container run -it --dns 1.1.1.1 --dns 8.8.8.8 alpine:1119 
/ # cat /etc/resolv.conf
search magedu.com
nameserver 1.1.1.1
nameserver 8.8.8.8

容器内和宿主机之间复制文件 cp

1
2
3
4
5
6
7
# docker container cp --help
Usage: docker container cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH
docker container cp [OPTIONS] SRC_PATH CONTAINER:DEST_PATH

Options:
-a, --archive Archive mode (copy all uid/gid information)
-L, --follow-link Always follow symbol link in SRC_PATH

使用systemd控制容器运行

范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# /lib/systemd/system/hello.service
[Unit]
Description=Hello World
After=docker.service
Requires=docker.service
[Service]
TimeoutStartSec=0
ExecStartPre=-/usr/bin/docker kill busybox-hello
ExecStartPre=-/usr/bin/docker rm busybox-hello
ExecStartPre=/usr/bin/docker pull busybox
ExecStart=/usr/bin/docker run --name busybox-hello busybox /bin/sh -c "while true; do echo Hello World; sleep 1; done"
ExecStop=/usr/bin/docker kill busybox-hello
[Install]
WantedBy=multi-user.target

传递环境变量

docker container -edocker container --env-file

范例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
docker run \
-d \
--name mysql-test1 \
-v /data/mysql:/var/lib/mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-e MYSQL_DATABASE=wordpress \
-e MYSQL_USER=wpuser \
-e MYSQL_PASSWORD=123456 \
mysql:5.7.30

# 或
docker run \
-d \
--name mysql-test2 \
-v /root/mysql/:/etc/mysql/conf.d \
-v /data/mysql2:/var/lib/mysql \
-p 3307:3306 \
--env-file=env.list \
mysql:5.7.30

cat env.list
MYSQL_ROOT_PASSWORD=123456
MYSQL_DATABASE=wordpress
MYSQL_USER=wpuser
MYSQL_PASSWORD=wppass

镜像结构和原理

镜像就是创建容器的模板,含有启动容器所需要的文件系统及所需要的内容,因此镜像主要用于方便和快速的创建并启动容器

镜像理由是一层一层的文件系统:Union FS(联合文件系统),可以将几层目录挂载到一起(类似俄罗斯套娃),形成一个虚拟文件系统,虚拟文件系统的目录结构就像普通linux目录结构一样,镜像通过这些文件,再加上宿主机的内核共同构成了一个linux的虚拟环境,每一层文件系统叫做一层layer,联合文件系统可以对每一层文件系统设置三种权限:readonly、readwrite、writeout-able。但是镜像中每一层文件系统都是只读的,构建镜像的时候,从一个最基本的操作系统开始,每个构建提交的操作都相当与做一层的修改,增加了一层文件系统,一层层往上叠加,上层的修改会覆盖底层该位置的可见性,当使用镜像的时候,我们只会看见一个整体,并不知道里面有几层,实际上也不需要知道

一个典型的Linux文件系统由bootfs和rootfs两部分组成

bootfs(boot file system)主要包含bootloader和kernel,bootloader主要用于引导加载kernel。系统刚启动时会加载bootfs文件系统,kernel加载到内存后,接管系统的控制权,bootfs就会被umount掉

rootfs(root file system)就是我们看到的/dev、/proc、/bin、/etc等目录和文件,不同的linux发行版本(如ubuntu和centos)主要在rootfs这一层会有所区别

一般的镜像通常都比较小,镜像直接调用宿主机的内核,镜像中只提供rootfs,也就是只需包括最基本的命令、配置文件和程序库等相关文件就可以了

容器、镜像和父镜像关系:

alpine 介绍

Alpine 操作系统是一个面向安全的轻型 Linux 发行版。它不同于通常 Linux 发行版,Alpine 采用了musl libc 和 busybox 以减小系统的体积和运行时资源消耗,但功能上比 busybox 又完善的多,因此得到开源社区越来越多的青睐。在保持瘦身的同时,Alpine 还提供了自己的包管理工具 apk,可以通过https://pkgs.alpinelinux.org/packages 网站上查询包信息,也可以直接通过 apk 命令直接查询和安装各种软件。

Alpine 由非商业组织维护的,支持广泛场景的 Linux发行版,它特别为资深/重度Linux用户而优化,关注安全,性能和资源效能。Alpine 镜像可以适用于更多常用场景,并且是一个优秀的可以适用于生产的基础系统/环境。

Alpine Docker 镜像也继承了 Alpine Linux 发行版的这些优势。相比于其他 Docker 镜像,它的容量非常小,仅仅只有 5 MB 左右(对比 Ubuntu 系列镜像接近 200 MB),且拥有非常友好的包管理机制。官方镜像来自 docker-alpine 项目。

目前 Docker 官方已开始推荐使用 Alpine 替代之前的 Ubuntu 做为基础镜像环境。这样会带来多个好处。包括镜像下载速度加快,镜像安全性提高,主机之间的切换更方便,占用更少磁盘空间等。

1
2
3
4
5
6
7
8
9
10
11
12
#修改源替换成阿里源:将/etc/apk/repositories中的 dl-cdn.alpinelinux.org 改成 mirrors.aliyun.com
sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/' /etc/apk/repositories
#更新源
apk update
# 查找可用软件包
apk search [vim]
# 列出软件信息
apk info [vim]
#安装软件
apk add vim
#删除软件
apk del openssh openntp vim

搜索镜像

如果联网下载,一般不会使用命令搜索,而是去官网搜索

docker镜像加速

登录阿里云 –> 容器镜像服务 –> 镜像中心 –> 镜像加速器

1
2
3
4
5
6
7
8
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://3417nt4m.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

docker image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# docker help image
Usage: docker image COMMAND

Commands:
build Build an image from a Dockerfile
history Show the history of an image
import Import the contents from a tarball to create a filesystem image
inspect Display detailed information on one or more images
load Load an image from a tar archive or STDIN
ls List images
prune Remove unused images
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rm Remove one or more images
save Save one or more images to a tar archive (streamed to STDOUT by default)
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE

下载镜像 pull

1
2
3
4
5
6
7
8
# docker help pull
docker pull [OPTIONS] NAME[:TAG|@DIGEST]

Options:
-a, --all-tags Download all tagged images in the repository
--disable-content-trust Skip image verification (default true)
--platform string Set platform if server is multi-platform capable
-q, --quiet Suppress verbose output
  • NAME:镜像名,仓库服务器:端口/项目名称/镜像名称
  • :TAG:版本号,如果不指定:TAG,则下载最新版镜像
1
2
3
4
5
6
7
[root@ubuntu1804 ~]#docker pull hello-world
Using default tag: latest #默认下载最新版本
latest: Pulling from library/hello-world
1b930d010525: Pull complete #分层下载
Digest: sha256:9572f7cdcee8591948c2963463447a53466950b3fc15a247fcad1917ca215a2f #摘要
Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest #下载的完整地址

下载后的镜像位于:

1
/var/lib/docker/overlay2

查看本地镜像 ls

1
2
3
4
5
6
7
8
9
docker image ls [OPTIONS] [REPOSITORY[:TAG]]

Options:
-a, --all Show all images (default hides intermediate images)
--digests Show digests
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print images using a Go template
--no-trunc Don't truncate output
-q, --quiet Only show numeric IDs

镜像导出 save

将本地镜像到处为一个文件(tar格式),然后复制到其他服务器,导入使用

1
2
3
4
5
# docker help image save
Usage: docker image save [OPTIONS] IMAGE [IMAGE...]

Options:
-o, --output string Write to a file, instead of STDOUT

常见用法:以下两种用法等价

1
2
docker save -o /path/file.tar IMAGE1 IMAGE2 ...
docker save IMAGE1 IMAGE2 ... > /path/file.tar

镜像导入 load

docker image save 导出的镜像压缩文件再导入

1
2
3
4
5
6
7
# docker help image load

Usage: docker image load [OPTIONS]

Options:
-i, --input string Read from tar archive file, instead of STDIN
-q, --quiet Suppress the load output

常见用法:以下两种用法等价

1
2
docker load -i /data/myimages.tar
docker load < /data/myimages.tar

删除镜像 rm

删除本地镜像

1
2
3
4
5
6
7
8
9
# docker help image rm
Usage: docker image rm [OPTIONS] IMAGE [IMAGE...]

Aliases:
rm, rmi, remove

Options:
-f, --force Force removal of the image # 强制删除
--no-prune Do not delete untagged parents
1
alias rmi='docker image ls -aq | xargs -n1 docker image rm'

镜像打标签 tag

给镜像打标签,类似于起别名,但通常要遵守一定的命名规范,才可以上传到指定的仓库

1
docker image tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]

TARGET_IMAGE[:TAG]格式一般为:仓库主机FQDN或IP[:端口]/项目名(或用户名)/image名字:版本

tag 默认为 latest

先tag给镜像打标签,然后再save导出镜像,拷贝到其他机器,其他机器可以load导入

安装和删除方法

官方文档:https://docs.docker.com/engine/install/
ubuntu:https://docs.docker.com/engine/install/ubuntu/
centos:https://docs.docker.com/install/linux/docker-ce/centos/
阿里云文档:https://developer.aliyun.com/mirror/docker-ce

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# ubuntuu
$ sudo apt-get update
$ sudo apt-get -y install \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
$ curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository \
"deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \
$(lsb_release -cs) \
stable"
$ sudo apt-get update
$ sudo apt -y install docker-ce

# 以上是直接安装最新版本,推荐安装时指定版本
$ apt-cache madison docker-ce
$ sudo apt -y install docker-ce=<VERSION_STRING>

二进制安装:https://docs.docker.com/install/linux/docker-ce/binaries/
https://mirrors.aliyun.com/docker-ce/linux/static/stable/x86_64/

配置文件

docker-ce 配置文件:

1
/etc/docker/daemon.json

docker registry 配置文件:

1
2
3
4
# ubuntu,来自containerd.io软件包
/etc/containerd/config.toml
# centos
/etc/containers/registries.conf

docker 相关信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
lujinkai@Z510:~$ sudo docker system info
Client:
Debug Mode: false #client 端是否开启 debug

Server:
Containers: 3 #当前主机运行的容器总数
Running: 0 #有几个容器是正在运行的
Paused: 0 #有几个容器是暂停的
Stopped: 3 #有几个容器是停止的
Images: 4 #当前服务器的镜像数
Server Version: 19.03.13 #服务端版本
Storage Driver: overlay2 #正在使用的存储引擎
Backing Filesystem: extfs #后端文件系统,即服务器的磁盘文件系统
Supports d_type: true #是否支持 d_type
Native Overlay Diff: true #是否支持差异数据存储
Logging Driver: json-file #日志类型
Cgroup Driver: cgroupfs #Cgroups 类型
Plugins: #插件
Volume: local #卷
Network: bridge host ipvlan macvlan null overlay # overlay 跨主机通信
#日志类型
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive #是否支持 swarm
Runtimes: runc #已安装的runtime
Default Runtime: runc #默认使用的容器runtime
Init Binary: docker-init #初始化容器的守护进程,即 pid 为 1 的进程
containerd version: 8fba4e9a7d01810a393d5d25a3621dc101981175 #版本
runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd #runc 版本
init version: fec3683 #init 版本
Security Options: #安全选项
apparmor #安全模块,https://docs.docker.com/engine/security/apparmor/
seccomp #安全计算模块,即制容器操作,https://docs.docker.com/engine/security/seccomp/
Profile: default #默认的配置文件
Kernel Version: 5.4.0-53-generic #宿主机内核版本
Operating System: Ubuntu 20.04.1 LTS #宿主机操作系统
OSType: linux #宿主机操作系统类型
Architecture: x86_64 #宿主机架构
CPUs: 4 #宿主机 CPU 数量
Total Memory: 15.56GiB #宿主机总内存
Name: Z510 #宿主机 hostname
ID: 7FJX:7VKN:2YGG:VKRB:5KKA:DB7C:KNLC:UW2N:XH3E:EVEG:OSQJ:EEKV #宿主机 ID
Docker Root Dir: /var/lib/docker #宿主机关于docker数据的保存目录
Debug Mode: false #server 端是否开启 debug
Registry: https://index.docker.io/v1/ #仓库路径
Labels:
Experimental: false #是否测试版
Insecure Registries:
127.0.0.0/8 #非安全的镜像仓库
Registry Mirrors:
https://3417nt4m.mirror.aliyuncs.com/ #镜像仓库
Live Restore Enabled: false #是否开启活动重启 (重启docker-daemon 不关闭容器 )

WARNING: No swap limit support #系统警告信息 (没有开启 swap 资源限制 )

解决上述SWAP报警提示:

1
2
3
4
5
6
7
# vim /etc/default/grub
...
GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0 swapaccount=1" #修改此行
...

sudo update-grub
sudo reboot

docker0 网卡

在docker安装启动之后,默认会生成一个名称为docker0的网卡,默认IP地址为172.17.0.1的网卡

docker 存储引擎

docker官方推荐首选存储引擎为overlay2,需要磁盘分区支持d-type功能

docker 服务进程

docker相关的四个进程:

  • dockerd:服务端程序,被client直接访问,父进程为宿主机的systemd守护进程
  • docker-proxy:每个进程docker-proxy实现对应一个需要网络通信的容器,管理宿主机和容器的之间端口映射,其父进程为dockerd,如果容器不需要网络则无需启动
  • containerd:被dockerd进程调用以实现与runc交互
  • containerd-shim:真正运行容器的载体,每个容器对应一个containerd-shim进程,其父进程为containerd

containerd-shim 命令

容器的创建与管理过程

  1. dockerd通过grpc和containerd模块通信,由libcontainerd负责,通信的socket:/run/containerd/containerd.sock
  2. containerd 在 dockerd 启动时被启动,然后containerd启动grpc请求监听,containerd处理请求,根据请求作出相应动作
  3. run/start/exec容器,containerd拉起一个container-shim,并进行相应的操作
  4. container-shim被拉起后,start/exec/create拉起runc进程,通过exit、control文件和containerd通信,通过父子进程关系和sigchld监控容器中进程状态
  5. 在整个容器生命周期中,container通过epoll监控容器文件、事件

gRPC

gPRC是谷歌开发的一款高性能、开源和通用的RPC框架,支持众多语言客户端

docker 服务管理

docker 服务基于 C/S 架构,可以实现基于本地和远程方式进行管理

范例:docker服务添加标签

1
2
3
4
5
6
7
8
9
vim /lib/systemd/system/docker.service
# 修改如下行
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --label="name=docker1"

docker info
...
Labels:
name=docker1 #此处显示添加的标签
...

docker的主要目标:一次封装,到处运行

容器和虚拟机技术比较:

  • 容器内的应用直接运行在宿主机的内核之上,容器并没有自己的内核,也不需要虚拟硬件,相当轻量化
  • 容器间是互相隔离,每个容器内都有一个属于自己的独立文件系统、进程空间、网络空间、用户空间等,所以在同一个宿主机上的多个容器之间彼此不会相互影响

docker 的组成

docker 官网:http://www.docker.com
帮助文档:https://docs.docker.com/
docker 镜像:https://hub.docker.com/
docker 中文网站:http://www.docker.org.cn/

镜像和容器:

镜像可以理解为是一个模板,创建实例使用的模板,本质就是一些程序文件的合集
容器是从镜像生成对外提供服务的一个或一组服务,本质就是将镜像中的程序启动后生成的进程

namespace

命名空间,linux底层概念,在内核层实现,容器使用namespce技术实现容器间相互隔离

  • mnt namespace:隔离根,即chroot技术
  • ipc namespace:隔离进程间通信
  • uts namespace:隔离系统信息
  • pid namespace:隔离进程号
  • net namespace:隔离网络
  • user namespce:隔离用户

Cgroups

Cgroups:Control Groups

Cgroups 最主要的作用,就是限制一个进程组能够使用的资源上限,包括CPU、内存、磁盘、网络带宽等等。此外,还能够对进程进行优先级设置,资源的计量以及资源的控制(比如 将进程挂起和恢复等操作)

利用Cgroups,宿主机可以对容器进行资源分配限制,比如CPU、内存等

容器核心技术

容器规范

容器除了docker,还有rkt、Pouch等,所有容器都要遵守标准的容器规范,这个规范由一个叫OCI的组织定,目前OCI一共发布了两个规范,分别是 runtime specimage fortmat spec,只要遵守这两个规范,就可以保证容器的可移植性和相互可操作性。

容器 runtime

runtime是真正运行容器的地方,因此为了运行不同的容器,runtime需要和操作系统内核紧密合作、相互支持,以便为容器提供相应的运行环境

runtime类型:lxc、libcontainer、runc、rkt

docker早期的runtime类型是lxc,现在是runc

容器管理工具

管理工具连接runtime与用户,对用户提供图形或命令方式操作,然后管理工具将用户操作传递给runtime执行

  • lxc 的 管理工具是 lxc
  • rkt 的 管理工具是 rkt cli
  • runc 的管理工具是 docker engine,docker engine包含daemon和cli两部分额,大家经常提到的docker就是docker engine

容器定义工具

容器定义工具允许用户定义容器的属性和内容,以方便容器能够被保存、共享和重建

docker image:是docker容器的模板,runtime依据docker image创建容器

dockerfile:包含N个命令的文本文件,通过dockerfile创建出docker image

镜像仓库 Registry

  • docker hub:docker官方的公共仓库,已经保存了大量的常用镜像,可以方便大家直接使用
  • 阿里云、网易等第三方镜像的公共仓库
  • image registry:docker 官方提供的私有仓库部署工具,无web管理界面,目前使用较少
  • harbor:vmware 提供的自带web界面自带认证功能的镜像私有仓库,目前有很多公司使用

容器编排工具

  • docker compose:docker 官方实现单机的容器的编排工具
  • docker swarm:docker 官方开发的容器编排引擎
  • Mesos+Marathon:Mesos是Apache下的开源分布式资源管理框架,它被称为是分布式系统的内核。Mesos最初是由加州大学伯克利分校的AMPLab开发的,后在Twitter得到广泛使用。通用的集群组员调度平台,mesos(资源分配)与marathon(容器编排平台)一起提供容器编排引擎功能
  • Kubernetes:google主导开发的容器编排引擎,内部项目为Borg,且其同时支持 docker 和CoreOS,当前已成为容器编排工具事实上的标准