Linux进阶¶
1. 常用命令¶
1.1. 系统网络¶
1.1.1 磁盘空间¶
1.1.2 df -h¶
显示已经挂载的分区列表
(base) moluo@ubuntu:~$ df -h
文件系统 容量 已用 可用 已用% 挂载点
udev 4.8G 0 4.8G 0% /dev
tmpfs 979M 1.9M 977M 1% /run
/dev/sda5 49G 30G 17G 65% /
tmpfs 4.8G 0 4.8G 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 4.8G 0 4.8G 0% /sys/fs/cgroup
/dev/loop0 128K 128K 0 100% /snap/bare/5
/dev/loop1 56M 56M 0 100% /snap/core18/2790
ls -lSr | more¶
注意:
ls -lS 表示列出当前目录下的所有子目录与子文件,并根据文件大小,进行排序(从大到小)
ls -lSR 表示列出当前目录下的目录与文件(包含内部多层所有目录与文件),并根据文件大小,进行排序(从大到小)
以尺寸大小排列文件和目录 【从小到大】
(base) moluo@ubuntu:~/Desktop/sunday/sunday_api/sunday_api/apps/users$ ls -lSr | more
总用量 48
-rw-rw-r-- 1 moluo moluo 0 Nov 2 02:09 __init__.py
-rw-rw-r-- 1 moluo moluo 60 Nov 2 02:09 tests.py
-rw-rw-r-- 1 moluo moluo 63 Nov 2 02:09 admin.py
-rw-rw-r-- 1 moluo moluo 142 Nov 2 02:09 apps.py
-rw-rw-r-- 1 moluo moluo 536 Nov 7 19:01 urls.py
-rw-rw-r-- 1 moluo moluo 2923 Nov 6 18:07 models.py
-rw-rw-r-- 1 moluo moluo 3521 Nov 6 18:08 serializers.py
drwxrwxr-x 2 moluo moluo 4096 Nov 8 00:47 __pycache__
drwxrwxr-x 3 moluo moluo 4096 Nov 6 18:07 migrations
-rw-rw-r-- 1 moluo moluo 13695 Nov 8 00:47 views.py
du -sh 目录1 目录2 ...*¶
统计指定1个或多个目录的文件大小(占用磁盘空间),多个目录使用英文空格隔开
du -sk * | sort -rn¶
以容量大小为依据依次显示文件和目录的大小 ,单位是KB
(base) moluo@ubuntu:~/Desktop/sunday/sunday_web$ du -sk * | sort -rn
245068 node_modules
1860 src
428 public
32 yarn.lock
4 vite.config.js
4 README.md
4 package.json
4 index.html
1.1.2 网络进程¶
ping¶
尝试往指定IP/域名对应的服务器发送数据包,常用于检测网络是否通畅。
ping 网络地址/IP
ping www.baidu.com -c 3 -i 2 -c 表示发送的数据的次数 -i 表示发送数据的间隔时间(单位:秒)
(base) moluo@ubuntu:~/Desktop/sunday/sunday_web$ ping www.baidu.com -c 4 -i 5
PING www.a.shifen.com (110.242.68.3) 56(84) bytes of data.
64 比特,来自 110.242.68.3 (110.242.68.3): icmp_seq=1 ttl=128 时间=12.9 毫秒
64 比特,来自 110.242.68.3 (110.242.68.3): icmp_seq=2 ttl=128 时间=12.6 毫秒
64 比特,来自 110.242.68.3 (110.242.68.3): icmp_seq=3 ttl=128 时间=13.1 毫秒
64 比特,来自 110.242.68.3 (110.242.68.3): icmp_seq=4 ttl=128 时间=14.7 毫秒
ip a¶
查看网卡信息
网卡信息
lo 表示本地回环网卡,是单词loop的缩写, 每个操作系统都会有的自带。默认IP地址:
127.0.0.1或者::1ens33 或者eth0,表示以太网卡,使用在互联网使用的网卡。
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
# ens33 表示以太网卡
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:0c:29:59:68:45 brd ff:ff:ff:ff:ff:ff
inet 192.168.233.151/24 brd 10.0.0.255 scope global dynamic ens33
valid_lft 1784sec preferred_lft 1784sec
inet6 fe80::20c:29ff:fe59:6845/64 scope link
valid_lft forever preferred_lft forever
ifconfig¶
查看网卡配置
命令需要安装:
ContOS: yum install -y net-tools
Ubuntu: sudo apt install -y net-tools
基本使用:
ifconfig 查看所有网卡信息
ifconfig ens33 查看指定网卡信息
(base) moluo@ubuntu:~/Desktop/sunday/sunday_web$ ifconfig
# ens33 以太网卡
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
# inet 表示网卡IPv4地址,netmask 子网掩码 , broadcast 广播地址
inet 192.168.233.132 netmask 255.255.255.0 broadcast 192.168.233.255
# inet6 表示网卡IPv6地址
inet6 fe80::50c4:44d:ec03:82c1 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:46:bc:cd txqueuelen 1000 (以太网)
# RX 使用当前网卡接受数据的统计数据,packets数据包 bytes字节
RX packets 13450 bytes 16833838 (16.8 MB)
RX errors 0 dropped 0 overruns 0 frame 0
# TX 使用当前网卡发送数据的统计数据,packets数据包 bytes字节
TX packets 6692 bytes 548780 (548.7 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
# lo 回环网卡
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (本地环回)
RX packets 903 bytes 201018 (201.0 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 903 bytes 201018 (201.0 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
cat /etc/resolv.conf¶
查看网关信息或DNS服务器地址
[root@iZbp1bao6pwa01zj7sar6hZ ~]# cat /etc/resolv.conf
# Generated by NetworkManager
nameserver 100.100.2.136
nameserver 100.100.2.138
启用/关闭网络管理服务¶
小于20.04的Ubuntu:
sudo apt install ifupdown 安装命令
ifup ens33 # 启动指定网卡 ifdown ens33 # 关闭指定网卡[慎用,可以重启网络吗,但是禁止远程手动关闭网卡]
大于等于20.04的Ubuntu:
关闭网络管理服务:service network-manager stop # 关闭网络管理服务以后,并不影响网卡,但是如果没有网卡,则网络管理服务是无法启动。
启动网络管理服务 :service network-manager start
域名和路由¶
| 命令 | 描述 |
|---|---|
route -n |
打印路由表,可以在第一行查看当前电脑的路由表 Gateway表示网管 netmask表示子网掩码 |
hostname |
显示当前系统的主机名 |
hostnamectl set-hostname <新的主机名> |
修改当前系统的主机名 |
host 域名 |
对域名解析成IP地址,也可以使用nslookup命令来解析。 ContOS: yum install -y bind-utils |
whois 域名 |
获取域名的相关注册信息 ContOS: yum install -y whois.x86_64 |
操作内容:
route -n # 打印路由表,可以在第一行查看当前电脑的路由表 Gateway表示网管 netmask表示子网掩码
(base) moluo@ubuntu:~$ route -n 内核 IP 路由表 目标 网关 子网掩码 标志 跃点 引用 使用 接口 0.0.0.0 192.168.233.2 0.0.0.0 UG 20100 0 0 ens33 169.254.0.0 0.0.0.0 255.255.0.0 U 1000 0 0 ens33 192.168.233.0 0.0.0.0 255.255.255.0 U 100 0 0 ens33hostname # 显示当前系统的主机名 hostnamectl set-hostname moluo # 修改主机名
host www.baidu.com # 对域名解析成IP地址,也可以对IP地址解析成域名
(base) moluo@ubuntu:~$ host www.baidu.com www.baidu.com is an alias for www.a.shifen.com. www.a.shifen.com has address 110.242.68.3 www.a.shifen.com has address 110.242.68.4 www.a.shifen.com has IPv6 address 2408:871a:2100:2:0:ff:b09f:237 www.a.shifen.com has IPv6 address 2408:871a:2100:3:0:ff:b025:348d
ps¶
ps ef 列出当前系统下所有的进程¶
(base) moluo@ubuntu:~$ ps ef
PID TTY STAT TIME COMMAND
11840 pts/1 Ss 0:00 bash LC_TELEPHONE=en_US.UTF-8 GJS_DEBUG_OUTPUT=stderr GDMSESSION=ubuntu DESKTOP_SESSI
12025 pts/1 S+ 0:00 \_ ssh root@47.98.246.242 SHELL=/bin/bash SESSION_MANAGER=local/ubuntu:@/tmp/.ICE-un
10572 pts/0 Ss 0:00 bash LC_TELEPHONE=en_US.UTF-8 GDMSESSION=ubuntu GJS_DEBUG_OUTPUT=stderr DESKTOP_SESSI
12098 pts/0 R+ 0:00 \_ ps ef SHELL=/bin/bash SESSION_MANAGER=local/ubuntu:@/tmp/.ICE-unix/2773,unix/ubun
2605 tty2 Ssl+ 0:00 /usr/lib/gdm3/gdm-x-session --run-script env GNOME_SHELL_SESSION_MODE=ubuntu /usr/bin
2607 tty2 Sl+ 1:01 \_ /usr/lib/xorg/Xorg vt2 -displayfd 3 -auth /run/user/1000/gdm/Xauthority -backgrou
2646 tty2 Sl+ 0:00 \_ /usr/libexec/gnome-session-binary --systemd --systemd --session=ubuntu LANGUAGE=z
2728 tty2 Z+ 0:00 \_ [fcitx] <defunct>
ps aux¶
列出当前系统下所有的进程的详细信息
(base) moluo@ubuntu:~$ ps aux
# user 表示当前进程的所有者用户
# pid 表示当前进程的ID
# CPU 当前进程使用的CPU资源
# MEM 当前进程使用的内存资源
# TTY 哪个用户开启在哪个终端下开启的
# STAT 当前进程状态
# START TIME 当前进程的启动时间
# COMMAND 启动进程时的终端命令
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.3 0.1 168956 12960 ? Ss 16:36 0:19 /sbin/init auto noprompt
root 2 0.0 0.0 0 0 ? S 16:36 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? I< 16:36 0:00 [rcu_gp]
root 4 0.0 0.0 0 0 ? I< 16:36 0:00 [rcu_par_gp]
root 5 0.0 0.0 0 0 ? I< 16:36 0:00 [slub_flushwq]
root 6 0.0 0.0 0 0 ? I< 16:36 0:00 [netns]
root 8 0.0 0.0 0 0 ? I< 16:36 0:00 [kworker/0:0H-events_highpri]
root 10 0.0 0.0 0 0 ? I< 16:36 0:00 [mm_percpu_wq]
root 11 0.0 0.0 0 0 ? S 16:36 0:00 [rcu_tasks_rude_]
root 12 0.0 0.0 0 0 ? S 16:36 0:00 [rcu_tasks_trace]
root 13 0.0 0.0 0 0 ? S 16:36 0:00 [ksoftirqd/0]
netstat -tup¶
提示:
netstat -tupl # 显示系统的所有网络连接以及对应的进程ID【详细】
显示系统的所有网络连接以及对应的进程ID
(base) moluo@ubuntu:~$ netstat -tup
(并非所有进程都能被检测到,所有非本用户的进程信息将不会显示,如果想看到所有信息,则必须切换到 root 用户)
激活Internet连接 (w/o 服务器)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 1 gitlab.example.co:33400 tsa01s11-in-f14.1:https SYN_SENT 12587/chrome --type
tcp 0 0 gitlab.example.co:45020 110.242.69.174:https ESTABLISHED 12587/chrome --type
tcp 0 0 gitlab.example.co:33444 119.249.102.35:https ESTABLISHED 12587/chrome --type
tcp 0 0 gitlab.example.co:37970 58.254.137.226:https ESTABLISHED 12587/chrome --type
tcp 0 0 gitlab.example.co:45022 110.242.69.174:https ESTABLISHED 12587/chrome --type
tcp 0 0 gitlab.example.co:43856 tsa01s09-in-f13.1:https ESTABLISHED 12587/chrome --type
tcp 0 0 gitlab.example.co:57854 111.206.208.245:https ESTABLISHED 12587/chrome --type
tcp 0 0 gitlab.example.co:59904 110.242.68.4:https ESTABLISHED 12587/chrome --type
tcp 0 0 gitlab.example.co:50972 110.242.68.3:https ESTABLISHED 12587/chrome --type
tcp 0 0 gitlab.example.co:52602 47.98.246.242:ssh ESTABLISHED 12025/ssh
tcp 0 1 gitlab.example.co:33402 tsa01s11-in-f14.1:https SYN_SENT 12587/chrome --type
kill¶
杀死包含指定程序名的进程¶
使用 kill -9 <进程ID> 杀死指定进程,步骤如下:
- 先查看指定程序的进程ID ,
ps aux | grep -i <程序名或关键字>grep -i 表示不区分大小写,匹配内容
(base) moluo@ubuntu:~$ ps aux | grep chrome moluo 12545 1.6 2.0 885696 204748 ? Sl 18:16 0:17 /opt/google/chrome/chrome moluo 12556 0.0 0.5 271468 53992 ? S 18:16 0:00 /opt/google/chrome/chrome --type=zygote --no-zygote-sandbox moluo 12557 0.0 0.5 271468 55036 ? S 18:16 0:00 /opt/google/chrome/chrome --type=zygote moluo 12558 0.0 0.0 10776 4272 ? S 18:16 0:00 /opt/google/chrome/nacl_helper moluo 12561 0.0 0.1 271468 15184 ? S 18:16 0:00 /opt/google/chrome/chrome --type=zygote moluo 13018 0.0 0.0 12136 720 pts/0 S+ 18:33 0:00 grep --color=auto chrome
- 根据上面第二列的PID提示,使用kill -9 即可。
查看当前使用指定端口的程序相关信息¶
# lsof -i:<端口>
# 例如:lsof -i:8000 表示查看当前系统中监听8000端口的程序。
(base) moluo@ubuntu:~$ lsof -i:8000
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
python 13329 moluo 5u IPv4 438001 0t0 TCP localhost:8000 (LISTEN)
如果需要单独提取监听端口的程序的PID(进程ID),则可以使用-t参数进行指定。
杀死占用指定端口的程序¶
# 所以我们可以使用 kill -9 `lsof -t -i:端口`
# 查找端口对应的进程ID,并强制结束, CentOS中安装:yum install -y lsof
kill -9 `lsof -t -i:端口`
kill -9 $(lsof -t -i:端口) # 等价于上一句
基于进程名称来杀死进程¶
pkill -f <进程名> # 表示结束vi关键字相关的进程
# CentOS中安装:yum install -y psmisc
pkill -f chrome # pkill -9 chrome 可以使用
基于服务名杀死进程¶
1.1.3 网络抓包¶
tcpdump¶
网络抓包命令,类似谷歌浏览器中的F12中的network,但是比F12强大
# ContOS安装:yum install -y tcpdump
tcpdump tcp # 监听整个操作系统所有使用默认以太网卡的tcp请求和响应,默认使用以太网卡
tcpdump tcp port 8000 # 对80端口的所有请求进行抓包
tcpdump -i ens33 # 对ens33网卡进行网络监听
tcpdump -i lo tcp port 8000 # 对回环网卡进行网络监听 tcp网络协议下的8000端口的数据包
tcpdump -i lo host www.sunday.cn # 对本地设置www.sunday.cn域名的访问数据进行监听。
top¶
Linux的进程监控工具,类似window的资源管理器
top - 11:33:05 up 15 days, 17:13, 2 users, load average: 0.00, 0.00, 0.00
Tasks: 110 total, 1 running, 109 sleeping, 0 stopped, 0 zombie
%Cpu(s): 0.2 us, 0.2 sy, 0.0 ni, 99.5 id, 0.0 wa, 0.0 hi, 0.2 si, 0.0 st
MiB Mem : 1685.1 total, 694.1 free, 233.5 used, 757.6 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 1267.3 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
789 root 20 0 485040 23808 9748 S 0.3 1.4 23:22.29 tuned
2191 root 20 0 815936 13084 6928 S 0.3 0.8 11:39.75 aliyun-service
69676 root 10 -10 153860 23880 16756 S 0.3 1.4 62:38.53 AliYunDunMonito
1 root 20 0 172816 10792 7916 S 0.0 0.6 0:15.88 systemd
2 root 20 0 0 0 0 S 0.0 0.0 0:00.12 kthreadd
3 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_gp
4 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 rcu_par_gp
5 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 slub_flushwq
7 root 0 -20 0 0 0 I 0.0 0.0 0:00.00 kworker/0:0H-events_highpri
9 root 20 0 0 0 0 I 0.0 0.0 0:04.40 kworker/u4:0-xfs-blockgc/vda3
top
第一行 (uptime)
系统时间 主机运行时间(up) 用户连接数(users,) (load average)系统5分钟内,10分钟内,15分钟的平均负载
第二行:进程信息
进程总数(totals) 正在运行的进程数(running,) 睡眠的进程数(sleeping,) 停止的进程数(stoped) 僵尸进程数(zombie)
第三行:cpu信息
1.5 us:用户空间所占CPU百分比【用户态】
0.9 sy:内核空间占用CPU百分比【内核态、系统态】
0.0 ni:用户进程空间内改变过优先级的进程占用CPU百分比
97.5 id:空闲CPU百分比
0.2 wa:等待输入输出的CPU时间百分比
0.0 hi:硬件CPU中断占用百分比
0.0 si:软中断占用百分比
0.0 st:虚拟机占用百分比
第四行:内存信息(与第五行的信息类似与free命令)
8053444 total:物理内存总量
7779224 used:已使用的内存总量
274220 free:空闲的内存总量(free+used=total)
359212 buffers:用作内核缓存的内存量
第五行:swap信息
8265724 total:交换分区总量
33840 used:已使用的交换分区总量
8231884 free:空闲交换区总量
4358088 cached Mem:缓冲的交换区总量,内存中的内容被换出到交换区,然后又被换入到内存,但是使用过的交换区没有被覆盖,交换区的这些内容已存在于内存中的交换区的大小,相应的内存再次被换出时可不必再对交换区写入。
ss -ntl¶
查看系统程序监听的端口情况
netstat -oan¶
显示所有连接和监听端口,以数字形式显示地址和端口号,并显示与每个连接相关的进程 ID
1.2 系统时间¶
针对CentOS的时间设置,网络配时。
工作中,往往公司里面的服务器对外提供web服务时,为了考虑安全性问题,都会采用高可用性的架构,例如:分布式集群结构或者微服务架构,子弹头架构等等。在跨时区系统架构下,基于同一个业务,要保证时间同步,否则会出现因为时区不一致的问题,导致不同时区的业务不同步,如果要求时间精度很高的情况下,我们还需要专门配置一台时间服务器。
# 设置系统时区位亚洲/上海
timedatectl set-timezone Asia/Shanghai
# CentOS: yum install -y chrony
# systemctl start chronyd
针对linux/Ubuntu时间需要设置成网络配时的话,可以按以下方式:
sudo tzselect
# 选项Asia 4
# 选项China 10
# 选项beijing 1
# 选项Yes 1
# 复制时区文件
sudo cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 安装ntp时间服务器
sudo apt install -y ntpdate
# 同步ntp时间服务器
sudo ntpdate time.windows.com
# 将系统时间与网络同步
sudo ntpdate cn.pool.ntp.org
# 将时间写入硬件
sudo hwclock --systohc
# 重启Ubuntu
reboot
date¶
date +%F # 按YYYY-mm-dd 格式输出年月日
date +%T # 按HH:MM:SS 格式输出时分秒
date +%F%n%T # 按 YYYY-mm-dd HH:MM:SS 格式输出年月日时分秒,%n 表示中间加个空格
1.3 计划任务¶
* * * * * mysqldump -root -p123 数据库名 > $(date +%F)-数据库名.sql
计划任务(scheduled tasks,也可以使用cron表示计划任务)是操作系统提供给系统使用者用于完成周期性任务的功能。在windows效果如下:
Linux查看计划任务服务是否运行¶
系统计划任务的时间粒度最小是分钟
# ubuntu/CentOS下都默认安装了,可以通过以下命令来确认。有绿色图标或者 active (running) 表示当前程序正在正常运行。
# ubuntu下的计划任务程序名叫 cron,而centOS下的计划任务程序名叫 crond
systemctl status crond
systemctl status cron
# 列出所有任务计划
crontab -l
# Linux下的计划任务不管新建还是编辑或者删除都是通过crontab -e 修改配置文件来完成的,所以打开并编辑计划任务的配置文件保存,计划任务即生效。
crontab -e
# 在界面化(有桌面)Linux下,首次使用crontab -e 需要选择编辑器,这里选vim.basic:
# Select an editor. To change later, run 'select-editor'.
# 1. /bin/nano <---- easiest
# 2. /usr/bin/vim.basic
# 3. /usr/bin/vim.tiny
# 4. /bin/ed
# Choose 1-4 [1]: 2
# 删除所有计划任务,慎用!
crontab -r
# 如果要删除单个计划任务,直接通过crontab -e 打开计划任务的配置文件,删除任务配置即可。
cron定时任务配置¶
Cron表达式自动生成:https://cron.qqe2.com/
例: 设置一个每分钟执行一次的定时任务
crontab -e # 打开定时任务配置文件,进行编辑
# 写入定时任务代码
# 快捷键 i 进入vim的编辑模型,并输入计划任务。计划任务中只识别绝对路径!!!
* * * * * echo "山外青山楼外青楼" >> /home/1.html
# 如果将来不需要执行这个任务,直接通过crontab -e 进去找到并删除即可。
* * * * * echo `date` >> /1.log
计划任务相关:
# 强调!所有命令操作的文件路径一定要用绝对路径来写!!!
# 每分钟执行一次命令
* * * * * 执行命令
# * * * * * python /home/1.py
# 下面3句也是每分钟执行一次
*/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,...60 * * * * 执行命令
1-60 * * * * 执行命令
# 每小时的0,15,30,45分钟执行命令
0,15,30,45 * * * * 执行命令
# 等价于下面这句:
*/15 * * * * 执行命令
# 在上午8-11点的第5和第15分钟执行命令
5,15 8-11 * * * 执行命令
# 等价于
5,15 8,9,10,11 * * * 执行命令 # 每天的8:05,8:15,9:05,0:15,10:05, 10:15, 11:05,11:15分执行命令
# 每晚21:30执行命令
30 21 * * * 执行命令
# 每天早上6点,中午12点,执行命令
0 6,12,18,0 * * * 执行命令
# 等价于
# 0 */6 * * * 执行命令
# 每周六、日的凌晨1:30执行命令
30 1 * * 6,0 执行命令
# 每周一到周五的凌晨1点,清空/tmp目录的所有文件
0 1 * * 1-5 rm -rf /tmp/*
#每月的5,15,25日的16:45执行命令
45 16 5,15,25 * * 执行命令
# 每个星期一的上午8点到11点的03分和15分执行命令
03,15 8-11 * * 1 执行命令
# 每月1号凌晨1:30,定时备份数据库school到/home/data目录下
30 1 1 * * mysqldump -uroot -p123 school>/home/data/school.sql
# 每年的1月1号的00:00分执行一次命令
0 0 1 1 * print("新年快乐")
注意:
系统提供的计划任务的周期时间最小粒度是分钟。如果要实现时间粒度更小的周期任务,可以自己采用程序来实现或者安装第三方的计划任务程序。
1.4 链接操作¶
Linux下所谓的链接文件,其实就是类似windows 下的快捷方式的文件。
Linux的作用是主要为了保证源文件的安全和调用路径方便而使用的。
Linux下链接文件有2种:软链接(Symbolic link)和硬链接(Hard link)。
注意:所有的链接文件使用的路径必须是绝对路径,否则链接无效,无效的链接的字样为红色闪烁。
删除链接文件并不影响源文件的内容,但是修改了链接的内容,会影响到源文件内容。
软连接与硬链接的区别:
- 软链接在Linux系统中,就是一个符号通道,方便访问和操作源文件的,只会关心源文件的路径而已。
- 硬链接在Linux系统中,就是一个特殊文件,与源文件的系统地址进行关联的,当源文件被删除以后,硬链接依然可以访问到原来的内容,所以硬链接更像是一种备份文件,但是与源文件同步关联的。不过当源文件被删除以后如果再次在同样的位置创建同名的文件,但硬链接不会与该文件再次关联。
- 当删除源文件时,软链接文件则会失效。如果删除源文件后同一个路径下出现新的同名文件,则软链接重新生效并与新源文件进行关联映射。
当源文件被删除或改名,软链接会失效,变成红色文字或闪烁。
当源文件被删除以后,硬链接还可以继续操作内容不被影响。当源文件被修改文件名或转移存储路径,硬链接还会继续关联源文件内容。
使用场景:
软链接的使用场景,主要是媒体文件(视频、图片)等内容,保证这些文件的内容安全与方便访问。
硬链接的使用场景,主要是配置文件(软件、项目)等内容,保证即便删除了源文件,链接也不会失效。
1.5 常用配置¶
1.5.1 网卡配置¶
一般在企业中,公司购买的服务器组建私有云时,需要运维配置网卡联网的。注意,公有云一般不需要。
企业中的服务器必须保证IP是固定的。
公有云:指代公司批量采购来自阿里云、腾讯云、华为云、亚马逊云、等平台的云服务器。
私有云:指代公司批量采购的物理服务器组建的云服务架构下的虚拟机(vm/k8s/docker)。
混合云:指代公有云和私有云混着来搭建的一台服务器架构。
在VMware中获取网关gateway,可以通过VMware左上角的编辑菜单->虚拟网络编辑器得到网关是192.168.233.2(自己看自己的)。
Ubuntu配置网卡¶
ubuntu的网卡配置文件保存路径:/etc/netplan/,配置文件的后缀是yaml。yaml是开发中常见的配置文件格式,自有语法格式。
注意:
开发中常见的配置文件:json、xml、ini、yaml、conf
# This is the network config written by 'subiquity'
network:
ethernets:
ens33:
dhcp4: no
dhcp6: no
addresses:
- 192.168.233.151/24
gateway4: 192.168.233.2
nameservers:
addresses: [192.168.233.2]
version: 2
IP与网关的地址,根据自己实际情况来修改。保存效果如下:
保存网卡配置,重启生效
注意:
- 上面的yaml配置文件,如果转换成python格式,则伪代码如下:
network={ // 网卡配置 "ethernets": { // 以太网卡配置 "ens33": { // 网卡名称 "dhcp4": False, // dbcp 是动态IPv4分配协议,表示告诉路由分配随机IPv4给当前网卡,no表示关闭这个协议。 "dhcp6": False, // dbcp 是动态IPv6分配协议,表示告诉路由分配随机IPv6给当前网卡,no表示关闭这个协议。 "addresses": [ // 指定当前网卡要想路由申请的IP地址/子网掩码 "192.168.233.151/24", // 151就是我们要申请的IP地址,取值范围:2-254 ], "gateway4": "192.168.233.2" // 指定IPv4的网关地址 nameservers: { // 设置DNS "addresses": [ "192.168.233.2" ] } } }, "version": 2 }
重启网卡以后,可以通过ipconfig 或者 ip a 命令查看网卡是否配置成功,如果显示的IP依然没有变化,则有2种可能:
当前IP被缓存了,需要重启确认是否成功。
- 如果重启了还没有效果,则有极大可能是IP被其他虚拟机占用了,此时可以尝试换一个IP地址,极少的可能是配置文件出错了。
yaml基本语法¶
yaml是"YAML Ain't a Markup Language"(YAML不是一种标记语言))的意思,是一种可读性高,用来表达数据序列化的格式。
基本语法:
- 大小写敏感,区分大小写
- 使用缩进表示层级关系,数组/对象的成员需要缩进
- 缩进不允许使用tab,只允许空格
- 缩进的空格数不重要,只要相同层级的元素左对齐即可(推荐缩进2个空格或者4个空格)
#表示注释- 文件名后缀:yaml,yml
数据类型:纯量(字符串、整型、浮点型、布尔型、空、日期、时间、日期时间)、数组、对象。
name: "小明" # 字符串变量【纯量】
age: 100 # 整型变量【纯量】
money: 7.50 # 浮点型变量【纯量】
sex: true # 布尔值变量【纯量】
data: null # 空变量【纯量】
data: ~ # 空变量【纯量】
time: 20:16:00 # 时间变量【纯量】
date: 2022-10-10 # 日期变量【纯量】
datetime: 2022-10-10 20:16:00 # 时间日期变量【纯量】
team: ["孙悟空", "猪八戒", "沙僧"] # 数组变量,类似python的列表
team: # 这种写法等价于上面的写法
- "孙悟空"
- "猪八戒"
- "沙僧"
person: {"name": "xiaoming", "age": 16} # 对象变量,类似python的字典
person: # 等价于上面的写法
name: "xiaoming"
age: 16
# 引用变量[数组/对象格式]
message: & demo
errmsg: "ok"
status: 0
data:
<<: *demo # 等价于下面一段,表示引用上面的&demo的变量内容
# message:
# errmsg: "ok"
# status: 0
CentOS配置网卡¶
CentOS的网卡地址:/etc/sysconfig/network-scripts
centos默认没有安装vim的话,可以使用vi编辑器。
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
# 设置路由分配IP地址的模式:dhcp 表示动态IP分配,static表示静态IP分配
BOOTPROTO=static
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
NAME=ens160
UUID=efb2bc72-c680-4775-9b40-6710d2d3d94e
DEVICE=ens160
ONBOOT=yes
# 根据自己的实际信息来填写!!!
IPADDR=192.168.233.152 # 当前系统要使用的地址,必须是其他的系统没有使用的。
GATEWAY=192.168.233.2 # 这个和上面ubuntu配置网卡一样,需要在vm的虚拟网络编辑器中查看
DNS1=192.168.233.2 # 这个和网关一样即可
DNS2=233.5.5.5 # 也可以是外网其他公司提供的开源的DNS服务器
NETMASK=255.255.255.0 # 子网掩码,需要在vm的虚拟网络编辑器中查看
修改后效果如下:
重启网卡
# nmcli connection reload && nmcli c down <网卡名称> && nmcli c up <网卡名称>
nmcli connection reload && nmcli c down ens160 && nmcli c up ens160
1.5.2 其他配置文件¶
# 修改机器名以及网卡,网卡等配置
/etc/sysconfig/network # CentOS
/etc/netplan # ubuntu
# linux的dns客户端配置文件,实现域名和ip的互相解析
/etc/resolv.conf # centos
# 本地dns解析文件,设定ip和域名的对应解析,开发测试最常用的临时域名解析
/etc/hosts
# 系统环境变量,,如PATH等,提供给所有的操作系统用户相关的环境变量,需要重启生效
/etc/profile # 格式: export 变量名=变量值
# 用户环境变量,仅提供当前系统用户使用
~/.bash_profile # centos
~/.profile # ubuntu
~/.bashrc # 命令的别名,格式:alias 别名命令='复杂命令'
# 使用上面的别名修改立即生效
source profile
# 存放可执行程序的目录,大多是系统管理命令
/usr/sbin # 超级root可以使用的系统命令,与/sbin一样
/usr/bin # 普通用户使用的系统命令
# 存放用户自编译安装软件的目录 > 等同于C:\Program files (windows)
/usr/local/src # 用户安装第三方软件的源码保存目录
/usr/local/sbin # 用户安装第三方软件后提供的超级权限的命令的保存目录
/usr/local/bin # 用户安装第三方软件后提供的普通命令的保存目录
# bash终端操作系统记录文件
.bash_history
1.5.3 环境变量¶
环境变量是系统全局变量,用于提供给软件/程序使用的,记录在操作系统里面的全局变量,往往是一些不能直接写在代码中的环境参数,如数据库的连接密码。
与windows下一样,Linux的环境变量也是分系统环境变量与用户环境变量,但是可用范围不同:
系统环境变量是提供给整个操作所有用户所有程序全局可用的。
用户环境变量是提供给当前登陆用户使用的。
环境变量的使用分两种情况:
- 直接在终端下使用
export 变量名=变量值来定义临时环境变量,这种方式定义的环境变量会立即生效,但是系统重启后就没有效果了。 - 直接在环境变量的配置文件中定义永久环境变量,这种方式定义的环境变量不会立即生效,需要使用
source 配置文件名来更新加载才能使用,当然系统重启后依然能使用。
系统环境变量¶
Linux下的系统环境变量:/etc/profile,如果要往环境变量中增加参数,则格式: export 变量名=变量值
# 使用vi 编辑器打开系统环境变量的配置文件
vi /etc/profile
# 跳转到行尾
GG
# 添加自己需要的全局参数,当然下面的MAX_SIZE没有任何意义,仅仅用于给大家演示效果,不能实际操作!!!
export MAX_SIZE=100
添加完环境变量以后,可以通过重启服务器的方式来更新环境变量,但是如果是运营服务器的话,是绝对不能重启更新的。
所以需要不停机更新(热更新)环境变量。
自然也可以查看环境变量。
如果要删除某个环境变量,则直接按添加环境变量的方式,打开/etc/profile,并把文件中要删除之前的添加参数的信息即可。自然,也是通过source /etc/profile来完成热更新的。
用户环境变量¶
用户的环境变量在Linux中不同的分支下,配置文件不同。
用户环境变量与系统环境变量的操作是一模一样的。所以这里,我们就不再演示了。
1.5.4 Shell命令的别名使用¶
在Linux中通常存在一些是具有多个参数的但是非常常用的命令。这些命令,Linux是允许使用者对这些附带参数的命令进行简单调用的。Linux提供了alias别名命令和~/.bashrc别名文件给开发者对复杂命令设置别名,方便简单调用。
命令别名的设置与环境变量类似,也有两种方式定义。
- 在终端下使用
alias命令定义的属于临时别名,系统重启后会失效。 - 在
~/.bashrc别名文件中定义的属于永久别名,系统重启后继续可用。
临时别名¶
永久别名¶
vi ~/.bashrc
# 在文件末尾加上对应的别名声明
alias psg='ps aux | grep '
# :wq 保存退出
source ~/.bashrc
# 测试是否有效果
psg ssh
1.6 网络安全¶
1.6.1 SELinux¶
SELinux(Security-Enhanced Linux,美国国家安全局NSA开发的访问控制机制),SELinux可以最大限度地保证Linux系统的安全。如果没有SELinux的话,Linux和windows的安全防范级别就是一样的了,很容易招受到黑客的攻击。 但是这玩意不是一般人能弄得明白。会的人不愿意折腾,不会的人一脸懵逼。所以市面上基本上大部分的公司都是采用其他的方式来保证主机的安全,而选择永久关闭SELinux。
ubuntu是Linux中提供给个人开发者的一个分支,所以默认是没有安装这个SELinux的。
# 临时关闭selinux
setenforce 0
# 开启selinux
# setenforce 1
# 查看启用状态,Enforcing运行状态,Permissive关闭状态,Disabled禁用状态
getenforce
# 永久关闭selinux,有2种方式:
# 方式1:
# sed -i "s/旧内容/新内容/g" 修改内容的文件
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config
# 方式2:
# 1. vim打开配置文件,将SELINUX=enforcing改为disabled
vim /etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
# SELINUX=enforcing
SELINUX=disabled
# 2. 保存退出,并检查状态
:wq
grep "SELINUX=disabled" /etc/selinux/config
# 出现disabled结果即表示修改成功,重启系统后使用getenforce就会变成disabled,表示禁用了。
1.6.2 防火墙¶
防火墙的作用就是限制数据进出的通道,也就是控制操作系统的端口或协议的开启和关闭。
而Ubuntu20.04一般都默认安装了ufw作为防火墙。
通用命令¶
| 命令 | 描述 |
|---|---|
| iptables -L | 查看防火墙规则[刚安装的机子是没有任何的规则配置的] |
| iptables -F | 清空防火墙规则 |
firewall¶
centos8默认使用firewall作为防火墙,Ubuntu早期版本也是使用这个的。
我们先了解怎么在Linux开启和关闭firewall服务的命令。
| 命令 | 描述 |
|---|---|
| systemctl status firewalld | 查看防火墙状态 |
| systemctl start firewalld | 开启防火墙,就是启动软件 |
| systemctl stop firewalld | 关闭防火墙,就是关闭软件 |
| systemctl enable firewalld | 设置防火墙开机自启 |
| systemctl disable firewalld | 关闭防火墙开机自启 |
| systemctl is-enabled firewalld | 检查防火墙是否是开机自启。 enabled表示已设置开机自启,disabled表示禁用 |
设置防火墙规则
| 命令 | 描述 |
|---|---|
| firewall-cmd --reload | 更新防火墙规则【重点:每次修改了防火墙规则必须更 新以后才生效!!!】 |
| firewall-cmd --list-ports | 查看所有关于端口设置的防火墙规则,也就是查看 所有打开的端口 |
| firewall-cmd --list-services | 查看所有关于服务设置的防火墙规则,也就是查看 所有允许的服务能接收和发送数据 |
| firewall-cmd --add-port=<端口号>/<协议> --permanent | 开放端口 --permanent表示永久生效的意思 |
| firewall-cmd --remove-port=<端口号>/<协议> --permanent | 关闭端口 --permanent表示永久生效的意思 |
| firewall-cmd --add-service=<服务名> --permanent | 开放服务 --permanent表示永久生效的意思 |
| firewall-cmd --remove-service=<服务名> --permanent | 关闭服务 --permanent表示永久生效的意思 |
防火墙的规则设置:
# 开放端口,需要使用才打开,否则千万不能打开。
firewall-cmd --add-port=21/tcp --permanent # 设置开放21端口,并永久生效 ftp
firewall-cmd --add-port=22/tcp --permanent # 设置开放22端口,并永久生效 ssh
firewall-cmd --add-port=25/tcp --permanent # 设置开放25端口,并永久生效,邮件发送服务器 smtp
firewall-cmd --add-port=80/tcp --permanent # 设置开放80端口,并永久生效 http
firewall-cmd --add-port=443/tcp --permanent # 设置开放443端口,并永久生效 https
firewall-cmd --add-port=465/tcp --permanent # 设置开放443端口,并永久生效,邮件发送服务器 smtps
firewall-cmd --add-port=3306/tcp --permanent # 设置开放3306端口,并永久生效 mysql
firewall-cmd --add-port=5432/tcp --permanent # 设置开放5432端口,并永久生效 postgreSQL
firewall-cmd --add-port=6379/tcp --permanent # 设置开放6379端口,并永久生效 redis
firewall-cmd --add-port=9000/tcp --permanent # 设置开放9000端口,并永久生效 nginx
firewall-cmd --add-port=9200/tcp --permanent # 设置开放9200端口,并永久生效 elasticsearch
firewall-cmd --add-port=9300/tcp --permanent # 设置开放9300端口,并永久生效 elasticsearch
firewall-cmd --add-port=27017/tcp --permanent # 设置开放6379端口,并永久生效 mongoDB
firewall-cmd --add-port=8000-8008/tcp --permanent # 设置开放8000至8008这9个连续的端口,并永久生效,仅用于测试,一般不开放
firewall-cmd --reload # 每次开发/关闭端口或服务,必须更新防火墙规则,否则不生效
firewall-cmd --list-ports # 列出当前已开放的所有端口
# 21/tcp 22/tcp 25/tcp 80/tcp 443/tcp 465/tcp 3306/tcp 5432/tcp 6379/tcp 8000-8008/tcp 9000/tcp 9200/tcp 9300/tcp 27017/tcp
# 关闭端口
firewall-cmd --remove-port=25/tcp --permanent # 设置关闭25端口,并永久生效,邮件发送服务器 smtp
firewall-cmd --remove-port=465/tcp --permanent # 设置关闭443端口,并永久生效,邮件发送服务器 smtps
firewall-cmd --remove-port=5432/tcp --permanent # 设置关闭5432端口,并永久生效 postgreSQL
firewall-cmd --remove-port=9000/tcp --permanent # 设置关闭9000端口,并永久生效 nginx
firewall-cmd --remove-port=9200/tcp --permanent # 设置关闭9200端口,并永久生效 elasticsearch
firewall-cmd --remove-port=9300/tcp --permanent # 设置关闭9300端口,并永久生效 elasticsearch
firewall-cmd --remove-port=27017/tcp --permanent # 设置关闭6379端口,并永久生效 mongoDB
firewall-cmd --remove-port=8000-8008/tcp --permanent # 设置关闭8000至8008这几个连续的端口,并永久生效
firewall-cmd --reload # 每次开发/关闭端口或服务,必须更新防火墙规则,否则不生效
firewall-cmd --list-ports # 列出当前已开放的所有端口
# 21/tcp 22/tcp 80/tcp 443/tcp 3306/tcp 6379/tcp
# 开放服务,前提是当前软件已经安装并运行了,否则虽然会设置成功,但是因为没有服务,所以没有效果
# firewall-cmd --add-service=ssh --permanent # 默认情况下Linux下的ssh都是默认开启的
firewall-cmd --add-service=mysql --permanent
firewall-cmd --reload
firewall-cmd --list-services
# 关闭服务
firewall-cmd --remove-service=mysql --permanent
firewall-cmd --reload
firewall-cmd --list-services
UFW¶
Ubuntu是面向个人开发者的Linux版本,所以默认情况下UFW是关闭状态的。
# 1.防火墙的开启和关闭
sudo ufw enable # 开启防火墙,开启之前,建议设置开放22号端口,否则只能在Linux本机先设置开放ssh协议对应的22号端口,否则无法使用ssh远程连接,会被拦截。
sudo ufw disable # 关闭防火墙
sudo ufw status # 查看防火墙状态,并列出所有规则。active表示开启,inactive表示关闭。默认关闭。
sudo ufw status verbose # 查看防火墙状态的详细信息,并列出所有规则。
# 开放端口
sudo ufw allow 22/tcp # 设置开发22端口 ssh
sudo ufw allow 80/tcp # 设置开放80端口 http
sudo ufw allow 443/tcp # 设置开放443端口 https
sudo ufw allow 3306/tcp # 设置开放3306端口 mysql
sudo ufw allow 6379/tcp # 设置开放6379端口 redis
# 关闭端口
sudo ufw delete allow 443/tcp # 设置关闭443端口,https
2. 软件管理¶
-
开发软件安装与配置
-
开发环境的搭建和项目的部署
不管是开发软件安装与配置,还是开发环境的搭建和项目的部署,实际上都是需要安装程序,而Linux系统下安装程序的方式无非2大类:
-
源码安装 -> 源码包
-
包管理器 -> 二进制可执行文件
2.1 软件包管理¶
Linux下最初只有tar.gz这样的源码包。但是Linux中的程序大多是小程序,程序与程序之间存在非常复杂的依赖关系,这些小程序的源码包的管理就是一个很让人头疼的问题。
dpkg(Debian package),是Debian软件包管理器的底层实现基础。
apt-get是早期Debian实现的包管理器,在ubuntu16.04以后新出炉的apt比apt-get更好用。但是apt毕竟是刚出的,所有有时候有些操作还是要使用apt-get的。
apt(Advanced Packaging Tool,Linux高级打包工具)是一款基于Debian分支的所有Linux发行版本的包管理器,构建于dpkg之上。
deb,是Debian软件包格式的文件扩展名。一般使用dpkg或apt安装的软件包都是这个扩展名。
deb包在 Linux操作系统中类似于windows中的 软件包(exe),几乎不需要什么复杂的编译即可通过鼠标点击安装使用。
rpm(Red-Hat Package Manager,红帽软件包管理器),是一款由红帽公司在apt基础上研发出来的包管理器。
用RPM工具可以将二进制程序进行打包,包被称为RPM包。RPM无法解决软件包的依赖关系,所以依赖yum自动解决软件依赖性。
yum(Yellow dog Updater, Modified)是一款在Fedora和RedHat以及CentOS中的软件包管理器的前端工具。基于RPM包管理,能够从指定的软件源服务器自动下载RPM包并且安装,可以自动处理依赖性关系,并且一次安装所有依赖的软件包,无须繁琐地一次次下载、安装。
说明:
debian/Ubuntu 的二进制安装包格式:deb,对应的包管理器:dpkg(无法管理依赖)、apt-get、apt
redhat/CentOS 的二进制安装包格式:rpm,对应的包管理器:rpm(无法管理依赖)、yum
dpkg[扩展]¶
| 命令 | 描述 |
|---|---|
| dpkg -i <包名.deb> | 安装包【前提是把deb包下载回来】 |
| dpkg -r <包名> | 删除包 |
| dpkg -P <包名> | 删除包(包括配置文件) |
| dpkg -L <包名> | 列出与该包关联的文件 |
| dpkg -l <包名> | 显示该包的版本 |
| dpkg --unpack <包名.deb> | 解开 deb 包的内容 |
| dpkg -S <包名关键字> | 搜索所属的包内容 |
| dpkg -l | 列出当前已安装的包 |
| dpkg -c <包名.deb> | 列出 deb 包的内容 |
| dpkg --configure <包名> | 配置包 |
apt¶
| apt 命令 | 取代的命令 | 命令的功能 |
|---|---|---|
| apt install -y <包名> | apt-get -y install <包名> | 安装软件包 -y 表示yes 不需要确认,直接操作 |
| apt remove -y <包名> | apt-get -y remove <包名> | 移除软件包 -y 表示yes 不需要确认,直接操作 |
| apt purge <包名> | apt-get purge <包名> | 移除软件包及配置文件 |
| apt update <包名> | apt-get update <包名> | 刷新存储库索引 |
| apt upgrade <包名> | apt-get upgrade <包名> | 升级所有可升级的软件包 |
| apt autoremove | apt-get autoremove | 自动删除不需要的包,自动删除依赖。 |
| apt full-upgrade <包名> | apt-get dist-upgrade <包名> | 在升级软件包时自动处理依赖关系 |
| apt search <关键字> | apt-cache search<关键字> | 搜索应用程序 |
| apt show <包名> | apt-cache show <包名> | 显示安装细节 |
| apt list | apt list | 列出包含条件的包(已安装,可升级等) |
rpm[扩展]¶
| 命令 | 描述 |
|---|---|
| rpm -ivh <包名.rpm> | 安装软件包 |
| rpm -e <包名.rpm> | 卸载软件包 |
| rpm -q 包名 | 查询包是否已经安装 |
| rpm -Uvh <包名.rpm> | 升级软件包 |
| rpm -qpi 包名.rpm | 查询软件包的描述信息 |
| rpm -qpl <包名.rpm> | 列出软件文件信息 |
yum¶
| 命令 | 描述 |
|---|---|
| yum install -y <包名> | 安装软件包 |
| yum reinstall -y <包名> | 重新安装软件包 |
| yum update -y <包名> | 升级软件包 |
| yum search <关键字> | 搜索包含关键字的软件包 |
| yum remove -y <包名> | 移除软件包 |
| yum clean all | 清除所有仓库缓存 |
| yum makecache | 创建新的仓库缓存 |
| yum repolist all | 列出所有仓库 |
| yum list all | 列出仓库所有软件包 |
| yum info 软件包名 | 查看软件包信息 |
| yum check-update | 检查可以更新的软件包 |
| yum grouplist | 查看系统中已安装的软件包 |
练习:
在centos中安装python3.11:
yum install -y python3.11
安装完成以后,可以使用 python3.11 进入python交互终端,能进入就表示安装成功了。
卸载命令:
yum remove -y python3.11
2.2 系统服务管理¶
linux中的安装包安装完成以后,一般是以系统服务提供给管理员进行使用的,可以控制这些服务的启动,关闭或重启等等。
大部分的linux发行版本中都会提供了一个service命令给管理员进行服务的调用。在新的linux发行版本中,还存在一个更加强大好用的工具,叫systemctl,并且systemctl兼容了service命令。
| 命令 | 描述 |
|---|---|
| service <服务名> start | 启动服务 |
| service <服务名> stop | 关闭服务 |
| service <服务名> restart | 重启服务 |
| service <服务名> status | 查看服务的运行状态 |
systemctl是一个非常强大的Linux的服务管理系统,为Linux系统的启动和管理提供一套完整的解决方案。systemctl的优点是功能强大,使用方便,缺点是体系庞大,非常复杂。它为Linux提供了一整套命令系统,涉及到系统管理的方方面面。这里我们先学习几个基础命令。
| 命令 | 描述 |
|---|---|
| systemctl restart <服务名> | 重启服务 |
| systemctl start <服务名> | 启动服务 |
| systemctl stop <服务名> | 停止服务 |
| systemctl status <服务名> | 查看服务状态【红色表示关闭、错误;绿色表示正常运行,白色表示启动中或重启中】 |
| systemctl enable <服务名> | 设置服务开机自启 |
| systemctl disable <服务名> | 关闭服务开机自启的设置 |
| systemctl is-enabled <服务名> | 检查服务是否设置了开机自启【enabled表示已设置开机自启,disabled表示禁用】 |
2.3 开发软件的安装和配置¶
2.3.1 python解析器安装¶
Centos系统下使用源码包安装python¶
源码安装软件的通用流程,如下:
0. 先删除已有低版本的同一个软件[例如,之前通过包管理器安装,系统默认提供的]
1. 添加/修改源[软件源]
2. 更新源
3. 去官网下载源码包
4. 解压源码包到指定目录,分配路径
5. 修改配置,基于当前操作系统的实际情况来修改配置
6. 安装依赖,编译&&编译安装[把源代码编译二进制可执行文件]
7. 配置系统服务,如果要开机自启的话,则添加系统服务并设置开机自启,如果不需要则不需要配置系统服务。
备份原来的源
# 切换到centos的系统源存储目录
cd /etc/yum.repos.d/
# 创建一个空目录,用于备份原来的源,防止新的源不能用,旧的源被删除或覆盖的情况出现。
mkdir repo_bak
# 把现有系统的源剪切到备份目录
mv *.repo repo_bak/
# 新增系统源
vi CentOS-Stream-BaseOS.repo
CentOS-Stream-BaseOS.repo,代码:
[baseos]
name=CentOS Stream $releasever - BaseOS
baseurl=https://mirrors.aliyun.com/centos/8-stream/BaseOS/x86_64/os/
https://mirrors.huaweicloud.com/centos/8-stream/BaseOS/x86_64/os/
https://mirrors.163.com/centos/8-stream/BaseOS/x86_64/os/
gpgcheck=1
enable=0
gpgkey=https://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-Official
[AppStream]
name=AppStream
baseurl=https://mirrors.aliyun.com/centos/8-stream/AppStream/x86_64/os/
https://mirrors.huaweicloud.com/centos/8-stream/AppStream/x86_64/os/
https://mirrors.163.com/centos/8-stream/AppStream/x86_64/os/
gpgcheck=1
enable=0
gpgkey=https://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-Official
[epel]
name=epel
baseurl=https://mirrors.aliyun.com/epel/8/Everything/x86_64/
gpgcheck=1
enable=0
gpgkey=https://mirrors.aliyun.com/epel/RPM-GPG-KEY-EPEL-8
[extras]
name=extras
baseurl=https://mirrors.aliyun.com/centos/8-stream/extras/x86_64/os/
gpgcheck=1
enable=0
gpgkey=https://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-Official
重建源缓存
下载python源码包
# 安装wget 是Linux常用的http请求工具,除了wget以外,还有curl也可以。
yum install -y wget
# 建议不要把所有文件保存到家目录下,建议发到以下目录
cd /usr/local/src
wget --no-check-certificate https://www.python.org/ftp/python/3.11.6/Python-3.11.6.tgz
# curl -O https://www.python.org/ftp/python/3.11.6/Python-3.11.6.tgz
下载python3编译的依赖包
3.解压缩源码包
4.进入源码包文件夹
5.编译且安装 (1) 进入源码包目录
(2) ls查看源码包内容
(3) 释放编译文件 Makefile
(4) 编译,使用gcc把源码编译成二进制文件
(5) 编译安装,根据configure的配置结果,把make编译生成的二进制文件按配置进行安装,如安装到/opt/python11/目录
(6) 进入/opt目录查看python31文件夹,我们要的python3.11都在这里了
(7) 更改linux的path环境变量,添加python相关的环境变量
一定要将python3.9的目录放在第一位
# 添加环境变量,在/etc/profile文件最后添加一行
# 记住一定要将python3的目录放在第一位
vi /etc/profile
PATH=$PATH:/opt/python39/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
:wq
为了永久生效path设置,添加到/etc/profile全局环境变量配置文件中 重载配置文件/etc/profile
经过上面的操作,我们就完成了python3.11解释器的源码编译安装。
当然,将来如果要卸载的话,可以直接在上面路径上,直接删除源码即可。
包管理器安装Python¶
# centOS
yum install -y python3.11 python3.11-pip && pip3 install setuptools
# Ubuntu
sudo apt install -y python3.9
# 默认python命令:python3.9,当然,如果要默认python指向python3.9,设置软链接即可。
sudo ln -s /usr/bin/python3.9 /usr/bin/python
2.3.2 Python虚拟环境安装¶
主流的虚拟环境管理工具:anaconda(miniconda3)、virtualenv(virtualenv的使用必须先安装好python解释器)
安装虚拟环境miniconda3,https://conda.io/en/latest/miniconda.html
anaconda是一个开发中常用的环境工具,但是安装过程中本身体量太大,内置将近200多个安装包,所以我们一般在公司服务器会使用miniconda来代替anaconda。miniconda本质上就是anaconda的轻量级版本,没有太多的内置的安装包。
CentOS下安装miniconda
cd /usr/local/src
wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-py311_23.9.0-0-Linux-x86_64.sh
# curl -O https://repo.anaconda.com/miniconda/Miniconda3-py311_23.9.0-0-Linux-x86_64.sh
bash Miniconda3-py311_23.9.0-0-Linux-x86_64.sh -b
# 经过上面操作,就表示miniconda安装就完成了。
# 接下来配置conda的相关环境信息,让linux能全局识别conda命令
# 在/etc/profile文件尾部添加conda的路径
vi /etc/profile
export ANACONDA_PATH=/root/miniconda3
export PATH=$PATH:$ANACONDA_PATH/bin
# :wq,保存退出,并重载配置,让配置生效
source /etc/profile
# 验证是否配置成功
conda --version
# 设置让base启动时不要默认进入base虚拟环境
conda config --set auto_activate_base false
python # 此处可以看到,我们还在全局环境下,并没有进入 conda 的 base全局虚拟环境,
# 所以可以通过conda创建虚拟环境,当然也可以进入conda默认提供的base全局虚拟环境中。
conda create -n djdemo python=3.11
# 进入虚拟环境[如果无法正常进入虚拟环境,则重新打开终端远程链接服务器即可]
source activate djdemo
# 1. 家目录下创建一个专门保存项目的目录,假设叫www
cd /home/
mkdir www && cd www
# 2. 安装Django
pip install django -i https://pypi.tuna.tsinghua.edu.cn/simple
# 3. 创建一个django项目,目录名为djdemo
django-admin startproject djdemo
# 4. 修改远程访问白名单,让客户端可以请求django项目
sed -i "s/ALLOWED_HOSTS = \[\]/ALLOWED_HOSTS = \[\"*\"\]/g" /home/www/djdemo/djdemo/settings.py
# 5. 因为服务器一般都会开启防火墙,所以要查看防火墙规则,是否已经开放了8000端口
firewall-cmd --list-ports
# 如果未开放,则操作如下开放端口:
firewall-cmd --add-port=8000/tcp --permanent
firewall-cmd --reload
# firewall-cmd --list-ports
# 5. 等一分钟左右让防火墙规则生效,就可以在windows或其他系统下,直接通过IP:8000再次即可访问。
python manage.py runserver 0.0.0.0:8000
2.3.3 MariaDB¶
MariaDB,与MySQL是同一个作者开发的中小数据库,MariaDB的出现是作者担心Oracle(甲骨文)公司收购MySQL后并闭源MySQL。所以MariaDB就是以MySQL的替代版本出现的,所以MariaDB与MySQL在使用上几乎一模一样。
MySQL有企业版[]和社区版[[Community (GPL,格努协议)]。
Unix-> 1969-> C语言(肯·汤姆森和丹尼斯·李奇)->贝尔实验室->at@t公司-> 版权-> BSD
开源软件运动-> 理查德·斯托曼->GPL-> 黑客(黑客->建设,骇客->破坏,红客-)>以爱国为主,从事的保护性的网络攻防活动)
2.3.3.1 安装使用¶
- 由于官网的MariaDB版本要比国内服务器商(如阿里云)的版本要高,所以我们应该优先使用官方的稳定版本
- 添加repo仓库配置,:wq保存退出。
[mariadb]
name=MariaDB
baseurl=https://mirrors.aliyun.com/mariadb/mariadb-11.2.1/yum/centos/8/x86_64/
module_hotfixes=1
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
官方源:https://mirror.mariadb.org/yum/11.2/centos/8/x86_64/
清华源:https://mirrors.tuna.tsinghua.edu.cn/mariadb/mariadb-11.2.1/yum/centos/8/x86_64/
阿里源:https://mirrors.aliyun.com/mariadb/mariadb-11.2.1/yum/centos/8/x86_64/
- 当MariaDB仓库地址添加好后,你可以通过下面的一行命令轻松安装 MariaDB。
- 启动mariadb服务
ss -ntl # 查看端口监听情况,mySQL/mariaDB默认使用3306端口
systemctl status mariadb # 设置开机启动,别名:systemctl status mysql
systemctl start mariadb # 启动MariaDB,别名:systemctl start mysql
# systemctl stop mariadb # 停止MariaDB,别名:systemctl stop mysql
# systemctl restart mariadb # 重启MariaDB,别名:systemctl restart mysql
systemctl enable mariadb # 设置开机启动,别名:systemctl enable mysql
rpm -ql MariaDB-server | grep /etc # 查看配置文件
- 可以使用 mariadb 或者 mysql 进入刚安装的MariaDB交互终端。
注意:
MariaDB安装成功以后,默认是没有设置root密码的,所以直接可以登陆。这不安全,因此需要自己给root修改密码。
- 解决中文乱码问题
(2) 添加以下配置文件(如图)
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
log-error=/var/log/mariadb.log
init_connect='SET NAMES utf8mb4'
skip-character-set-client-handshake=true
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
(3) 重启数据库
- mysql/mariadb安装配置成功以后的测试操作
-- 1 创建数据库
create database school;
show create database school\G;
-- 2 创建表
use school
create table student (id int auto_increment primary key, name char(11));
show create table student\G;
-- 3 插入数据
insert into student values (1, "王小明"), (2, "江小白");
-- 4 查看数据
select * from student;
- 创建用户分配权限
开发中都是采用单独分配账户提供给项目使用的,而root用户因为权限过大,所以是禁止提供远程登陆的。
-- 创建用户
-- create user 账号名@'终端地址' identified by '登录密码';
create user moluo@'%' identified by '123'; -- %表示任意主机,也就是可以允许远程登录
create user xiaoming@'%' identified by '123';
-- 分配权限【? grant 可以查看权限】
-- grant 权限 on 数据库.表名 to 账户@"主机名" -- 对特定数据库中的特定表授权
-- grant 权限 on 数据库.* to 账户@"主机名" -- 对特定数据库中的所有表给与授权
-- grant 权限1,权限2,权限3,....权限n on *.* to 账户@"主机名" -- 对所有库中的所有表给与多个授权
-- grant all privileges on *.* to 账户@"主机名" -- 对所有库和所有表授权所有权限,相当于root
grant all privileges on school.* to moluo@'%'; -- 给moluo用户在任意主机登录时, 拥有数据库school的所有权限
grant select,insert on school.* to xiaoming@'%'; -- 给xiaoming用户在任意主机登录时, 拥有数据库school的读取和添加数据权限
-- 移除权限
-- revoke 权限 on 数据库.表名 from 账户@"主机名";
-- 剔除moluo在任意主机下所有数据库中所有表的所有权限
-- revoke all privileges on *.* from moluo@"%";
-- 剔除xiaoming在任意主机下对于school数据库的任意表的添加数据权限
revoke insert on school.* from xiaoming@"%";
-- 删除用户,记得先剔除权限。
-- drop user 账户名@'主机名';
revoke all privileges on *.* from xiaoming@"%";
drop user xiaoming@'%'; -- 删除小明在任意主机登录的账户,慎用!!会导致数据库中的数据不一致的问题。
-- 修改管理员密码
alter user 'root'@'localhost' identified by '123';
- 删除匿名用户
use mysql
delete from user where password="";
delete from user where user="mysql";
# 补充系统用户
grant all privileges on *.* to 'mariadb.sys'@'localhost' identified by 'root';
2.3.3.2 卸载数据库¶
yum remove -y mariadb* # 移除软件包
rm -rf /var/lib/mysql # 删除数据目录,前提必须保证,里面的重要数据已经备份了。
rm -rf /etc/my.cnf* # 删除配置文件
2.3.3.3 主从复制¶
使用主从复制的目的是为了提高项目的数据安全和项目运行过程中可用性。
最早的时候MariaDB是为了替代MySQL出现,所以MariaDB尽可能的兼容了MySQL的所有功能,但是那么多年下来,毕竟2个公司在分别运营的独立项目,所以MariaDB与MySQL之间还是存在一些兼容性问题的:https://mariadb.com/kb/en/mariadb-vs-mysql-compatibility/。
MariaDB与MySQL之间虽然是替代关系,在实现主从复制时是不能混合使用的。要么MariaDB与MariaDB搭建组从,要么MySQL与MySQL搭建组从(在mysql8.0(MariaDB10.4)版本之前,可以实现交叉主从)。
数据库的主从复制往往伴随着项目代码操作的读写分离。
写操作:添加(insert)、删除(delete)、修改(update)-> 一主数据库 -> 10%
读操作:查询(select) -> 多从数据库 -> 90%
主从复制的默认一般分三种:1主1从,1主多从,多主多从(集群)
主从原理¶
主从复制七步曲(面试常问)
1. 主数据库(master,主人)写入数据之后, 会有data changes(数据变化)事件
2. 主数据库(master)有变化记录之后,将增删改的sql语句记录到本地的Binary log(二进制备份日志)中
3. 从库(slave,仆从,奴隶)会单独运行并一直开启着一个IO子线程(I/O thread)
4. 从库(slave)通过这个IO子线程去连接并读取主数据库(master)的Binary log(二进制日志)的内容,当然这需要从库要有主库的账号密码)
5. 从库(slave)会将读取到的数据写入到自己的Relay log(中继日志)中,这一步也是IO子线程的工作。
6. 从库(slave)还会单独运行并一直开启着另一个SQL子线程(SQL thread),该子线程将中继日志中的操作转化为SQL语句
7. 从库(slave)通过SQL子线程把转化的SQL语句写入到自己的数据库, 两边的数据就一致了。
主从是2个或多个数据库之间的数据同步:
- 主库的数据永远是最新的。
- 涉及网络请求,所以主库宕机了,从库的数据就停滞了,因此用户读取数据时,得到的数据可能是以前同步的。
- 主从必然会存在数据一致性问题。(所谓的数据一致性问题就是主库更新了数据,但是从库查不出来或查询到的是旧的数据,因为同步需要时间,那怕是0.00001秒)。
一主一从¶
(1) 准备工作
必须保证数据的大版本一致,数据库的类型一致。5.7->5.6 有可能存在数据兼容,5.1 -> 8.0 绝对出问题。8.0.4->8.0.26 绝对没问题
分配服务器
| 服务器 | IP | 描述 |
|---|---|---|
| 主数据库master | 192.168.233.152 | centos |
| 从数据库slave | 192.168.233.153 | ubuntu |
保证CentOS中防火墙已经开放了3306端口
# 如果主数据库所在的服务器开启了防火墙,必须要开放对应的端口
firewall-cmd --list-ports
firewall-cmd --add-port=3306/tcp --permanent
firewall-cmd --reload
保证Ubuntu中防火墙已经开发了3306端口
sudo passwd root # 如果是首次使用root,要初始化密码,并配置网卡
su root # 切换root用户
ufw enable # 开启防火墙,设置开放3306,22,80等端口
ufw status
sudo ufw allow 3306/tcp
因为MySQL8.0以后,binlog日志和MarilDB的binlog不兼容了,所以我们要么使用同样的mysql,要么使用同样的marilDB
所以我们在Ubuntu中安装MariaDB11.2.x版本。
# 卸载原有的MySQL或MariaDB
sudo apt-get remove mysql-*
# 删除原有的MySQL或MariaDB的所有数据库
dpkg -l | grep ^rc | awk '{print $2}' | sudo xargs dpkg -P
# 安装相关组件依赖
sudo apt install -y apt-transport-https ca-certificates software-properties-common
# 设置PGPkey
sudo apt-key adv --fetch-keys 'https://mariadb.org/mariadb_release_signing_key.asc'
# 新建source.list
sudo vim /etc/apt/sources.list.d/MariaDB.list
# Ubuntu20.04系统的MariaDB.list的内容如下:
deb [arch=amd64] https://mirrors.tuna.tsinghua.edu.cn/mariadb/repo/11.2/ubuntu focal main
deb-src https://mirrors.tuna.tsinghua.edu.cn/mariadb/repo/11.2/ubuntu focal main
# 更新源
sudo apt update
# 安装命令
sudo apt install -y mariadb-server mariadb-client
# 查看端口占用情况,可以发现ubuntu安装完MariaDB以后,已经启动并设置了开机自启操作
ss -ntl
# 启动数据库服务
systemctl start mariadb
systemctl status mariadb
# 接下来跟CentOS一样的操作,修改配置文件,设置root用户密码,并删除匿名用户。
# ubuntu的mysql配置文件是 /etc/mysql/my.cnf
vi /etc/mysql/my.cnf
# my.cnf内容如下:
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
log-error=/var/log/mariadb.log
init_connect='SET NAMES utf8mb4'
skip-character-set-client-handshake=true
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
# 保存配置,并重启mariaDB
:wq
systemctl restart mariadb
# 修改root密码
mysql
alter user 'root'@'localhost' identified by '123';
# 删除匿名用户
use mysql
delete from user where password="";
delete from user where user="mysql";
(2) 在CentOS系统上进行配置操作,按之前约定设置当前数据库为主数据库master,并设置binlog日志与服务器的唯一ID。
# 查看数据库状态
systemctl status mariadb
# 关闭mariadb
systemctl stop mariadb
# 修改配置文件
vi /etc/my.cnf
# 修改内容
# 解释:server-id服务的唯一标识(主从之间的server-id都必须不同);log-bin启动二进制日志名称为mysql-bin
[mysqld]
bind-address=0.0.0.0
server-id=1
log-bin=mysql-logbin
# :wq,
(3) 继续在CentOS上主数据库master上操作(创建一个新用号提供给从库,让从库通过该账号登陆主库并复制binlog)
# 开启mariadb
systemctl start mariadb
# 使用root用户登陆数据库
mysql -uroot -p
# 1.新建用于主从同步的用户slave01,允许登录的从库(务必是从库服务器所在地址)是'192.168.233.153'
# create user '账号'@'登陆IP' identified by '密码';
# 此处密码是举例,将来工作中肯定设置非常复杂的密码。
create user 'slave01'@'192.168.233.153' identified by 'slave01';
# 2.给从库账号授权,说明给slave01从库复制binlog日志的权限,在192.168.233.153从数据库服务器上复制
# replication slave 表示从机复制数据的权限
grant replication slave on *.* to 'slave01'@'192.168.233.153';
# 如果上面的IP弄错了,会导致从库无法连接主库。可以使用以下命令撤销权限,删除用户。
# revoke all privileges on *.* from 'slave01'@'192.168.233.153';
# drop user 'slave01'@'192.168.233.153';
# 因为前面初始化时,删除了mariadb.sys@localhost用户,会导致导出数据报错。所以我们重新添加回来。
grant all privileges on *.* to 'mariadb.sys'@'localhost' identified by 'root';
# 3.实现对主数据库进行锁表,让用户能读取数据不能写入数据,防止数据写入不断新增,导致数据复制失败
# 锁表的目的就是为了在主从复制完成之前,保持两台数据库的数据一致
flush table with read lock;
# 4.检查主库的状态, 并记录下binlog日志的文件名和最新数据的插入位置。这句是固定语句。
show master status;
# 效果如下:
# +---------------------+----------+--------------+------------------+
# | File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
# +---------------------+----------+--------------+------------------+
# | mysql-logbin.000001 | 2945 | | |
# +---------------------+----------+--------------+------------------+
# 实际开发中,binlog不一定00001,也可以运行很久的数据库,有可能000100,同样,文件位置也并非是2945
# 5.锁表后,一定要单独再打开一个SSH窗口连接到主数据库所在的服务器CentOS中,导出数据库的所有数据,
mysqldump -uroot -p --all-databases > /home/master.sql
# 6.确保数据导出后,没有数据插入,完毕再查看主库状态,如果还是上图的数值,则没有问题.
# 数值有变化,则需要从上面第3步重新执行。
mysql -uroot -p
show master status; # 还是883,则表示没有问题了。如果不是上面的数字,则需要重新锁表,导出数据。
(4) 在Ubuntu上的从库slave上进行操作
# 7. ubuntu中,使用scp将备份导出的数据文件下载到Slave从数据库所在服务器 192.168.233.152
su root
scp -r root@192.168.233.152:/home/master.sql /home/
# 2.导入数据到当前从库中
mysql -uroot -p
source /home/master.sql # 此处必须使用绝对路径,否则无法导入
exit
# 3.修改Slave从数据库的配置文件/etc/mysql/my.cnf,文件最后,写入从属配置。1主多从,建议server-id自增即可。
vi /etc/mysql/my.cnf
"""内容开始
[mysqld]
bind-address=0.0.0.0
server-id=2
read-only=true # 限制当前库,只能进行只读操作,不能写入数据到从库【对root无效,root至高无上】
replicate-do-db=sunday
replicate-do-db=school
"""内容结束 replicate-do-db 表示 仅仅同步的数据库有哪些?一行一个
# 4.重启从数据库,终端操作:
systemctl restart mariadb
# 5 配置复制的参数,Slave从库连接Master主库的配置,SQL语句如下:
mysql -uroot -p
change master to master_host='192.168.233.152', master_user='slave01', master_password='slave01', master_log_file='mysql-logbin.000001', master_log_pos=2945;
# 6.启动从库的同步开关,测试主从复制的情况,SQL语句如下:
start slave;
# 如果要停止从库的同步操作,使用命令:stop slave;
# 7.查看当前从数据库的复制状态,固定语句,查看从库的运行状态
show slave status\G;
(5) 再回到CentOS的主库master上进行操作
mysql -uroot -p
# 1. 最后再给主库解锁
unlock tables;
# 2. 最后在主库上刷新授权表
flush privileges;
# 3. 操作主库的数据,可以看到从库的数据已经同步过来了。
create database if not exists school charset=utf8mb4;
use school;
create table if not exists student(
id int auto_increment primary key,
name char(20)
) charset=utf8mb4;
insert into student values (1, "小明"), (2, "小红");
(6) 在从库上登录普通用户,尝试写入数据会报以下错误, 说明从库只读。但是只读对root没有效果。
练习:
完成2台或以上服务器实现MySQL8.0的主从同步。1主2从
2.3.3.4 读写分离¶
这里我们配置django实现数据库的读写分离,在settings.py或dev.py配置文件中的DATABASES中记录主从所有的服务器连接信息。代码:
# Database
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
DATABASES = {
# 主库
"master": {
"ENGINE": "django.db.backends.mysql",
"HOST": "192.168.233.152",
"PORT": 3306,
"NAME": "school",
"USER": "xiaohui",
"PASSWORD": "123456",
},
"slave01": {
"ENGINE": "django.db.backends.mysql",
"HOST": "192.168.233.153",
"PORT": 3306,
"NAME": "school",
"USER": "xiaohui",
"PASSWORD": "123456",
},
"slave02": {
"ENGINE": "django.db.backends.mysql",
"HOST": "192.168.233.154",
"PORT": 3306,
"NAME": "school",
"USER": "xiaohui",
"PASSWORD": "123456",
},
}
创建对应用户,在各个节点(node,表示项目架构下的每一个连接地址[进程/程序])下,一般保持同步,使用同样权限,同样账户名,同样的密码的用户,代码:
在主应用下新增数据库的读写路由类文件,db_router.py,代码:
import random
class Router(object):
"""数据库读写分离分发路由"""
def db_for_write(self, model, **hints): # 方法名固定,返回值就是databases配置项
"""写数据库[写库]"""
print(f"写2:")
return "master"
def db_for_read(self, model, **hints):
"""读数据库【从库】"""
db = random.choice(["slave01", "slave02"]) # 随机抽取一个数据库配置名,保证每一个从库都几率平等被调用到。
return db
def allow_relation(self, obj1, obj2, **hints):
"""
因为django的ORM查询操作,返回结果QuerySet具有惰性执行的特点,
所以存在,同一条ORM操作代码存在连接多个库的情况,例如,filter代码连接slave01,但是get代码执行时连接时slave02
# 所以为了避免报错,我们设置allow_relation的结果为True
"""
return True
接着,在配置文件settings.py中,增加配置如下:
2.3.4 redis¶
如果直接安装二进制程序的方式,命令如下:
# 这里我们在ubuntu下安装redis
apt install -y redis
systemctl start redis
redis-cli
# 卸载
apt remove -y redis
apt autoremove
在CentOS中,进行源码安装redis
1.从官网上下载redis源码
cd /usr/local/src
wget http://download.redis.io/releases/redis-7.2.3.tar.gz
# curl -O http://download.redis.io/releases/redis-7.2.3.tar.gz
2.解压缩
3.切换redis源码目录
4.编译源文件,src/目录下有编译好的redis指令 make install 安装到指定目录,默认在/usr/local/bin
7 创建一个redis的配置文件redis-6379.conf
# 创建一个单独的目录保存redis相关的配置,默认情况下在上面执行make install,系统已经在/etc/已经生成了一个redis.conf,如果为了方便将来完成主从,集群或者哨兵的配置。建议单独另外声明一个目录中。
mkdir -p /opt/redis/conf
# 创建一个单独的目录保存redis的数据库文件
mkdir -p /opt/redis/data/6379
# 创建一个单独的目录保存redis的日志文件
mkdir -p /opt/redis/log/6379
目录结构如下:
/opt/redis/
├── conf/ # 配置文件目录
├── data/ # 数据存储目录
│ └── 6379/ # 保存运行监听端口在6379的redis持久化数据文件
└── log/ # 日志存储目录
└── 6379/ # 运行监听端口在6379的redis的日志
创建一个运行端口在6379的redis实例。
添加以下配置:
port 6379
bind 0.0.0.0
daemonize yes
pidfile /opt/redis/data/6379/redis.pid
loglevel notice
logfile /opt/redis/log/6379/redis.log
dir /opt/redis/data/6379
protected-mode yes
dbfilename dump.rdb
rdbcompression yes
save 900 1
save 300 10
save 60 10000
appendonly yes
appendfilename appendonly.aof
appendfsync everysec
user default on nopass sanitize-payload ~* &* +@all
user fuguang on #a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3 ~* resetchannels +@all
redis配置文件详解
port 6379 # 运行在6379的redis数据库实例
bind 0.0.0.0 # 是否允许远程登陆redis服务端
daemonize yes # 后台运行redis,redis守护进程模式运行
pidfile /data/6379/redis.pid # 存放redis pid的文件
loglevel notice # 日志等级 debug, verbose, notice, warning
logfile /opt/redis/log/6379/redis.log # 指定redis日志文件的生成目录
protected-mode yes # 安全模式
rdbcompression yes # rdb备份数据时,是否压缩存储
# requirepass python # 设置redis的登录密码,在redis6.0一般的版本就不要使用这个配置项了,改成ACL机制创建的账号
# 因为默认情况下redis是基于内存操作的数据,因为redis如果重启的话,则会导致内存中数据丢失,所以redis提供了2种方式用于提供给开发者对数据进行持久化(把数据从内存中备份到硬盘中进行永久保存),RDB是默认开启的,而AOF是默认关闭的,在redis5.0以前只能开启其中一种,5.0以后推荐两种混合备份。
# 1. RDB(数据快照,数据文件格式是二进制格式文件)
# 相关的配置项:
# dir 设置快照数据文件的存储目录
# dbfilename 设置快照数据文件名
# save 设置快照的执行频率或备份策略
dir /opt/redis/data/6379 # 指定redis数据文件夹的目录
dbfilename dump.rdb # rdb备份数据的文件名,目录就是dir指定的
# 备份策略
save 900 1 # 在间隔900秒以内,如果累计有1次key的写操作,则执行一次RDB的备份操作
save 300 10 # 在间隔300秒以内,如果累计有10次key的写操作,则执行一次RDB的备份操作
save 60 10000 # 在间隔50秒以内,如果累计有10000次key的写操作,则执行一次RDB的备份操作
# 针对RDB的配置,存在一定的数据的安全风险,例如:redis运行过程中900秒内有唯一的1次key写入操作,但是在类似899秒时redis突然重启了,则会导致数据丢失,又或者300内有累计10次,结果在299秒时redis重启了,则会导致这10次写操作丢失了数据。基于此,Redis还提供了另一种持久化的策略:AOF
# 2. AOF(追加日志备份,类似MySQL的bin-log日志的命令记录,记录了redis操作过程中的每一个命令,不同的是mysql的是二进制文件,而AOF的备份日志是压缩格式而已,并非二进制)
# AOF日志备份功能默认是no,表示关闭,我们需要打开,所以设置为yes
appendonly yes
# AOF日志文件名,所在目录由dir来指定
appendfilename appendonly.aof
# AOF日志备份策略,共有3个可选值:
# no:表示等操作系统进行数据缓存同步到磁盘(快,不安全)
# always:表示每次redis写操作后手动调用fsync()将数据写到磁盘(慢,安全)
# everysec:表示每秒同步一次(折衷,默认值,工作中常用,最多只会丢失1秒数据)
# fsync()表示在底层C语言中Fork一个子进程进行异步操作
appendfsync everysec
8 启动redis服务端开放端口,并指定配置文件,如果不指定,则默认使用/etc/redis.conf
redis-server /opt/redis/conf/redis-6379.conf
# 查看redis是否启动成功。
ps aux | grep redis
# 出现如下内容表示启动成功。
# root 806399 0.0 0.2 63216 10624 ? Ssl 00:38 0:00 redis-server 0.0.0.0:6379
# root 806605 0.0 0.0 12356 1100 pts/0 R+ 00:38 0:00 grep --color=auto redis
# 开放端口
firewall-cmd --list-ports
firewall-cmd --add-port=6379/tcp --permanent
firewall-cmd --reload
9 使用redis
redis中也有主从复制读写分离,也可以基于集群模式、甚至还有哨兵模式。工作中现在一般配置这几个运行架构,我们后面需要到容器技术时,可以进行配置。
2.3.5 nginx¶
查看网站的web服务器
2.3.5.1 nginx是什么¶
nginx是一个开源免费的,高性能,高并发的web服务和代理服务软件。它是俄罗斯人lgor sysoev(伊戈尔·塞索耶夫)在2000开发的,在2004年将源代码开源出来供全球使用。类似的web服务代理软件还有apache、tomcat、IIS、uwsgi、gunicorn、uvicorn等。
nginx比传统的web服务器apache性能改进了许多,nginx占用的系统资源更少,支持更高的并发连接,有更高的访问效率。 nginx不但是一个优秀的web服务软件,还可以作为反向代理,负载均衡,以及缓存服务使用。 安装更为简单,方便,灵活,而且使用人多,所以衍生非常多的优秀的nginx插件模块,可以轻松实现各种业务场景的服务代理,例如:网盘服务器、直播服务器nginx-rtmp-module、邮箱服务器pop3,smtp等。。。
反向代理
负载均衡
说白了,就是一个人干的活,按一定的策略,分担给多个人一起完成。压力分担,流量分担。使用一组同等架构的服务器基于一定的策略,分担原来的一台服务器的流量压力
nginx的优势
1. 支持高并发,能支持几万并发连接
2. 资源消耗少,在3万并发连接下开启10个nginx线程消耗的内存不到200M(32C/16C/8C,16G/32G/128G)
3. 可以做http反向代理和负载均衡
4. 支持异步网络io,epoll事件模型【多线程/多进程、CPU->多道技术的应用(时间片)->IO多路复用->select/poll/epoll】
5. 是目前最优秀的静态网页web服务器【提供静态文件访问支持,html,css,js】
2.3.5.2 安装使用¶
CentOS编译安装nginx¶
- 安装nginx需要的依赖库
- 下载源码包
cd /usr/local/src
wget https://nginx.org/download/nginx-1.25.3.tar.gz
# curl -O https://nginx.org/download/nginx-1.25.3.tar.gz
- 解压缩源码包
- 配置生成
cd nginx-1.25.3
./configure --prefix=/opt/nginx-1.25.3 --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module
- 编译安装
- 启动nginx
# 把nginx作为全局命令使用,需要在/etc/prifile环境变量中添加nginx命令所在路径
vi /etc/profile
export PATH=$PATH:/opt/nginx-1.25.3/sbin
:wq
source /etc/profile
nginx # 启动nginx
nginx -s stop # 关闭nginx
nginx -s reload # 平滑重启 ,修改了nginx.conf之后,可以不重启服务,加载新的配置
# nginx安装成功以后,可通过80端口访问默认站点.默认站点在nginx安装目录下的html目录下,默认首页是index.html
# 防火墙确认开放80端口
# 开放端口
firewall-cmd --list-ports
firewall-cmd --add-port=80/tcp --permanent
firewall-cmd --reload
# 查看nginx默认配置文件:/opt/nginx-1.23.1/conf/nginx.conf
nginx -t
nginx配置文件分析¶
nginx核心配置文件
# nginx运行的系统用户身份,一般要么注释掉,要么就把nobody改成www或者nginx,前提是我们使用useradd 创建对应的用户和用户组
# user nobody;
# 工作进程数 (如果是双核2线程,可以设置为2*2=4,一般建议跟CPU的逻辑核数量一致,也可以使用auto,让nginx自己根据实际情况设置)
# nginx的2种工作模式:单进程(本地开发和测试,以单线程单进程模式) 和 多进程(master-worker,线上运营)
# worker_processes auto;
# 单个进程最大可打开文件数,因为nginx经常用于提供静态文件访问支持,所以往往运营时间长了就会出现单个进程打开文件超标,所以要设置。
# worker_rlimit_nofile 65535;
# 错误日志配置,如果不配置,则错误日志保存在安装路径下
# error_log logs/error.log;
# error_log logs/error.log notice;
# error_log logs/error.log info;
# 进程标识符
# pid logs/nginx.pid;
# nginx的事件处理机制,也就是IO多路复用事件模型
events {
worker_connections 102400;
# 单个工作进程的连接数,默认是1024,可以设置最大可以调整到102400以上
# nginx的最大并发连接数 = worker_processes * worker_connections
# use epoll;
# 设置nginx使用的IO多路复用的事件模型,默认不设置即可,nginx会采用当前系统最优的事件模型
# linux建议epoll,FreeBSD建议采用kqueue,window下不指定,采用select。
}
# nginx作为httpweb服务器的相关配置,站点配置server必须填写在http选项中。
http {
# 导入mime.types模块,让nginx能够识别各种各样的文件资源
include mime.types;
# nginx默认识别的mime.types
default_type application/octet-stream; # application/octet-stream 二进制流数据
# 设置客户端访问nginx的访问日志格式,main是一个标记符(变量),方便后面配置引用
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# 开启访问日志
access_log logs/access.log main;
# 单独开启错误日志
error_log logs/error.log main;
# Nginx在进行数据传输,会调用sendfile()函数进行数据压缩, Linux 2.0+ 以后的推出的一个系统调用。
# 对比一般的数据的网络传输sendfile会有更少的切换和更少的数据拷贝,传输的数据格式是视频,音频,压缩包等本身已经压缩的,开启sendfile只会浪费CPU性能。
sendfile on;
tcp_nopush on;
# 客户端保持连接时间,保持默认的65秒即可
#keepalive_timeout 0;
keepalive_timeout 65;
# 开启网络传输的数据gzip压缩[会额外消耗一定的cpu资源,但是会节约大量的出口带宽来提高访问速度,gzip压缩算法的使用会带来一定的安全隐患,不建议压缩二进制文件和大文件]
gzip on;
#低于1kb的资源不压缩
gzip_min_length 1k;
# 设置压缩级别,级别范围:1~9,数字越大压缩率越高,同时消耗cpu资源也越多,建议设置在5左右。
gzip_comp_level 5;
# 指定压缩哪些MIME类型的静态资源,多个空格隔开。不建议压缩图片,视频等二进制文件
gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css text/html application/json;
# web站点的虚拟主机,类似python的虚拟环境,这里的配置,会让nginx自动提供一个站点给外界访问的源【协议+IP/域名+端口绑定唯一性】
# nginx可以通过设置多个server配置项,提供多个站点的访问支持,每一个站点都可以对外提供一个目录以及目录下所有的内容的web浏览服务
# 一个server就代表一个站点,也可以理解为一个服务端的源,源是通过端口、域名/IP、协议进行区分。
server {
# 站点的访问端口,要允许外界访问,还需要设置防火墙开放端口
listen 80;
# 站点的访问域名地址
server_name localhost;
#charset koi8-r;
# 单个站点内部的访问日志access_log
# access_log logs/host.access.log main;
# location 地址模式匹配,也就是路由规则,location后面的是访问url路径,相当于django的正则路由一样, 这里的 / 表示根目录,也可以其他地址
# 每一个 server站点配置下,可以有多个location路由规则设置。
# 地址匹配成功以后,则会调用当前花括号的配置信息
location / {
# root 表示当前站点所在根目录,html这里是表示nginx安装根目录下的html目录,建议实际配置使用绝对路径。
root html;
# index 指定默认首页,如果有多个格式的默认首页,使用空格隔开,靠左优先
index index.html index.htm;
}
location /admin { # http://localhost:80/admin ---> http://localhost:81/main.html
# 请求代理(效果类似url地址转发)
proxy_pass http://localhost:81/main.html;
}
error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
2.3.5.3 nginx多虚拟主机¶
配置多虚拟主机的方法
- 在nginx.conf配置配置文件中,设置加载外部自定义的配置文件到nginx环境中。
nginx.conf,末行通过include 加载配置文件,代码:
# user nginx;
# group nginx;
worker_processes auto;
worker_rlimit_nofile 65535;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 102400;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
gzip on;
gzip_min_length 1k;
gzip_comp_level 5;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css text/html application/json;
server {
listen 80;
server_name localhost;
location / {
root /home/fuguang;
index index.html index.htm;
}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
# 表示导入/home/nginx目录下所有以conf作为文件末尾的所有配置文件
include /home/nginx/*.conf;
}
- 在/home/nginx下创建三个站点的nginx虚拟主机server配置文件。
mkdir -p /home/nginx/
touch /home/nginx/zhanqi.conf
touch /home/nginx/huya.conf
touch /home/nginx/douyu.conf
# 结构如下:
/home/nginx/
├── douyu.conf
├── huya.conf
└── zhanqi.conf
- 分别配置三个虚拟主机server代码。(斗鱼、虎牙、站旗)
代码:
server {
listen 80;
server_name www.douyu.com;
location / {
root /home/douyu;
index index.html;
}
}
# :wq
代码:
代码:
server {
listen 80;
server_name www.zhanqi.com;
location / {
root /home/zhanqi;
index index.html;
}
}
- 创建三个网站的源码存储目录
mkdir -p /home/{douyu,huya,zhanqi}
echo '<mate charset="utf-8">welcome to douyu!!!!!!!!' > /home/douyu/index.html
echo '<mate charset="utf-8">welcome to huya!!!!!!!!' > /home/huya/index.html
echo '<mate charset="utf-8">welcome to zhanqi!!!!!!!!' > /home/zhanqi/index.html
# index.html里面的内容自己随意定义
# 目录结构如下:
/home/web/
├── douyu/
│ └── index.html
├── huya/
│ └── index.html
└── zhanqi/
└── index.html
- 重启nginx服务(平滑重启)
- 配置域名解析
(1) 到阿里云或腾讯云等云服务商平台注册一个域名。在哪里购买服务器,就在哪里购买域名,否则回头还要迁移域名。
(2) 修改客户端本地HOSTS文件C:\Windows\System32\drivers\etc\hosts;其他系统:/etc/hosts
192.168.233.150 www.douyu.com
192.168.233.150 www.huya.com
192.168.233.150 www.zhanqi.com
DNS【域名解析服务器】
常用顶级域名服务商: # .com / .cn / .net / .org /.edu
douyu.com 192.168.233.150
二级域名:
www.douyu.com 192.168.233.150
api.douyu.com 192.168.233.151
db.douyu.com 10.0.0.135
三级域名:
mysql.db.douyu.com 192.168.233.150
mongodb.db.douyu.com 192.168.233.150
5 可以通过windows下的客户端浏览器直接访问,建议清除浏览器的浏览历史。
2.3.5.4 nginx状态信息查看¶
启用status状态,修改douyu站点的配置文件。
代码:
# 在server代码块下添加以下location配置
server {
listen 80;
server_name www.douyu.com;
location / {
root /opt/web/douyu;
index index.html index.htm;
}
location /status {
# 使用之前编译安装进来的插件http_stub_status_module
stub_status on;
}
}
3 重启nginx
4 通过域名/status访问状态信息
http://www.douyu.com/status
Active connections: 2
server accepts handled requests
43 43 73
Reading: 0 Writing: 1 Waiting: 1
# Active connections – 活跃的连接数量
# server accepts handled requests — 总共处理了43个连接 , 成功创建43次握手, 总共处理了73个请求。
# reading — 读取客户端的历史连接数。
# writing — 响应数据到客户端的历史数量。
# waiting — 开启 keep-alive 的情况下,这个值等于 active – (reading+writing), 意思就是 Nginx 已经处理完正在等候下一次请求指令的驻留连接。
2.3.5.5 创建自签名证书,开启https协议¶
创建生成自签名的CA证书:
cd /home/nginx
openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -days 3650 -out ca.crt
# Generating a RSA private key
# ..++++
# .++++
# writing new private key to 'ca.key'
# -----
# You are about to be asked to enter information that will be incorporated
# into your certificate request.
# What you are about to enter is what is called a Distinguished Name or a DN.
# There are quite a few fields but you can leave some blank
# For some fields there will be a default value,
# If you enter '.', the field will be left blank.
# -----
# 输入国家编码!中国是CN
Country Name (2 letter code) [XX]: CN
# 输入省份编码!省份的首字母大写拼音
State or Province Name (full name) []: BeiJing
# 输入城市编码!城市的首字母大写拼音
Locality Name (eg, city) [Default City]: Beijing
# 组织名称,输入公司名的全拼
Organization Name (eg, company) [Default Company Ltd]: Sunday.Ltd
# 组织单位名称,输入部分名的全拼
Organizational Unit Name (eg, section) []: edu
# 输入服务器名或者用户域名
Common Name (eg, your name or your server's hostname) []: www.douyu.com
# 组织或组织联系人的邮箱地址
Email Address []:649641514@qq.com
完成上面的内容填写以后,可以输入ll,查看得到的CA证书与证书秘钥
[root@localhost nginx]# ll
总用量 20
-rw-r--r-- 1 root root 2134 9月 22 16:15 ca.crt
-rw------- 1 root root 3272 9月 22 16:14 ca.key
接下来,就可以基于上面的CA签发证书给指定域名进行签发自签名证书
openssl req -newkey rsa:4096 -nodes -sha256 -keyout www.douyu.com.key -out www.douyu.com.csr
# Generating a RSA private key
# ................................................................++++
# ..........++++
# writing new private key to 'www.douyu.com.key'
# -----
# You are about to be asked to enter information that will be incorporated
# into your certificate request.
# What you are about to enter is what is called a Distinguished Name or a DN.
# There are quite a few fields but you can leave some blank
# For some fields there will be a default value,
# If you enter '.', the field will be left blank.
# -----
# 输入国家编码!中国是CN
Country Name (2 letter code) [XX]: CN
# 输入省份编码!省份的首字母大写拼音
State or Province Name (full name) []:BeiJing
# 输入城市编码!城市的首字母大写拼音
Locality Name (eg, city) [Default City]:Beijing
# 组织名称,输入公司名的全拼
Organization Name (eg, company) [Default Company Ltd]: douyu.com
# 组织单位名称,输入部分名的全拼
Organizational Unit Name (eg, section) []: douyu.com
# 输入服务器名或者用户域名
Common Name (eg, your name or your server's hostname) []: www.douyu.com
# 组织或组织联系人的邮箱地址
Email Address []:649641514@qq.com
Please enter the following 'extra' attributes
to be sent with your certificate request
# 质询密码,直接回车留空即可
A challenge password []:
# 可选公司名称,直接回车留空即可
An optional company name []:
完成上面操作以后,就得到了指定域名www.douyu.com的自签名证书。
[root@localhost nginx]# ll
总用量 32
-rw-r--r-- 1 root root 2134 9月 22 16:15 ca.crt
-rw------- 1 root root 3272 9月 22 16:14 ca.key
-rw-r--r-- 1 root root 1756 9月 22 16:17 www.douyu.com.csr
-rw------- 1 root root 3272 9月 22 16:16 www.douyu.com.key
向CA提交"信息"并注册签名证书
openssl x509 -req -days 3650 -in www.douyu.com.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out www.douyu.com.crt
# Signature ok
# subject=C = CN, ST = BeiJing, L = BeiJing, O = douyu.com, OU = douyu.com, CN = www.douyu.com, emailAddress = 649641514@qq.com
# Getting CA Private Key
完成上面操作以后,可以得到我们需要的自签名证书了。
[root@localhost nginx]# ll
总用量 36
-rw-r--r-- 1 root root 2134 9月 22 16:15 ca.crt
-rw------- 1 root root 3272 9月 22 16:14 ca.key
-rw-r--r-- 1 root root 41 9月 22 16:18 ca.srl # 签发记录
-rw-r--r-- 1 root root 2021 9月 22 16:18 www.douyu.com.crt # 真正的证书
-rw-r--r-- 1 root root 1756 9月 22 16:17 www.douyu.com.csr
-rw------- 1 root root 3272 9月 22 16:16 www.douyu.com.key
验证证书
openssl x509 -in www.douyu.com.crt -noout -text
# Certificate:
# Data:
# Version: 1 (0x0)
# Serial Number:
# 3b:c6:71:c5:c9:75:91:f2:aa:0c:50:2a:f7:dd:8f:f0:b0:d1:91:58
# Signature Algorithm: sha256WithRSAEncryption
# Issuer: C = CN, ST = BeiJing, L = Beijing, O = Odedu.Ltd, OU = edu, CN = www.douyu.com, emailAddress = 649641514@qq.com
# Validity
# Not Before: Sep 22 08:18:51 2022 GMT
# Not After : Sep 19 08:18:51 2032 GMT
# Subject: C = CN, ST = BeiJing, L = BeiJing, O = douyu.com, OU = douyu.com, CN = www.douyu.com, emailAddress = 649641514@qq.com
# Subject Public Key Info:
# Public Key Algorithm: rsaEncryption
# RSA Public-Key: (4096 bit)
# Modulus:
# 00:cb:4e:2b:bf:22:01:64:52:5f:5d:d2:25:aa:e1:
# ...
# 55:82:80:95:a6:14:58:ee:f8:f8:2f:6a:12:b6:ea:
# 58:ef:53
# Exponent: 65537 (0x10001)
# Signature Algorithm: sha256WithRSAEncryption
# 0a:04:e5:89:5e:52:2a:5d:6c:4d:8b:57:ae:17:ef:ab:ff:aa:
# .....
# 82:06:5f:04:2d:36:90:35
在nginx配置中,我们配置一个https协议的虚拟站点。
douyu.conf,代码如下:
# server {
# listen 80;
# server_name www.douyu.com;
# location / {
# root /home/douyu;
# index index.html;
# }
# location /status {
# stub_status on;
# }
# }
server {
listen 443 ssl;
server_name www.douyu.com;
ssl_certificate /home/nginx/www.douyu.com.crt;
ssl_certificate_key /home/nginx/www.douyu.com.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
root /home/douyu;
index index.html;
}
location /status {
stub_status on;
}
}
重启nginx。
再次打开浏览器,访问:https://www.douyu.com/。
需要对着浏览器屏幕,输入thisisunsafe即可访问。
2.3.5.6 对nginx的虚拟站点进行性能测试¶
# apache ab压测命令(简称:ab压测工具), 测试服务器对于并发请求和最大连接数的支撑能力。(数值尽量少一点,不要开太多)
# 我们通过ubuntu对centos进行压测测试
# ubuntu安装ab工具:
sudo apt install -y apache2-utils
# centos安装ab工具:
# yum install -y httpd-tools
# 修改/etc/hosts信息,让域名指向到centos中nginx的站点域名地址
vi /etc/hosts
192.168.233.152 www.douyu.com
192.168.233.152 www.huya.com
192.168.233.152 www.zhanqi.com
moluo@moluo:~$ ab -c 1000 -n 5000 https://www.douyu.com/status
This is ApacheBench, Version 2.3 <$Revision: 1843412 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking www.douyu.com (be patient)
Completed 500 requests
Completed 1000 requests
Completed 1500 requests
Completed 2000 requests
Completed 2500 requests
Completed 3000 requests
Completed 3500 requests
Completed 4000 requests
Completed 4500 requests
Completed 5000 requests
Finished 5000 requests
Server Software: nginx/1.25.3
Server Hostname: www.douyu.com
Server Port: 443
SSL/TLS Protocol: TLSv1.2,ECDHE-RSA-AES256-GCM-SHA384,4096,256
Server Temp Key: X25519 253 bits
TLS Server Name: www.douyu.com
Document Path: /status
Document Length: 109 bytes
Concurrency Level: 1000 # 当前ab请求服务器的并发请求数量
Time taken for tests: 22.469 seconds
Complete requests: 5000
Failed requests: 4999
(Connect: 0, Receive: 0, Length: 4999, Exceptions: 0)
Total transferred: 1277128 bytes
HTML transferred: 557128 bytes
Requests per second: 222.53 [#/sec] (mean) # 每秒处理完成的请求数量,是web服务器并发能力的体现
Time per request: 4493.704 [ms] (mean) # 处理完全部的请求所消耗的时间(ms)
Time per request: 4.494 [ms] (mean, across all concurrent requests) # 处理1个请求的消耗平均时间(ms)
Transfer rate: 55.51 [Kbytes/sec] received # 每秒响应请求数据的数据量(kb)
Connection Times (ms)
min mean[+/-sd] median max
Connect: 19 3082 1509.6 2449 16768
Processing: 1 88 118.8 34 1879
Waiting: 1 86 115.9 34 1878
Total: 264 3170 1562.0 2485 16813
Percentage of the requests served within a certain time (ms)
50% 2485
66% 3318
75% 3728
80% 3899
90% 5519
95% 6286
98% 6540
99% 9656
100% 16813 (longest request)
2.3.5.7 nginx访问日志¶
- 修改nginx.conf配置文件,启用访问日志功能。
2 重启nginx服务
3 用户访问我的网站,/opt/nginx-1.25.3/logs/access.log就有了日志
2.3.5.8 nginx访问控制¶
nginx提供的访问控制主要是针对整个站点或部分连接地址,设置访问客户端的白名单与黑名单(白名单是放行,黑名单是禁行,两者可以一起使用,但是容易冲突)。
这里,我们使用douyu.com站点来举例,修改nginx.conf配置文件,添加访问douyu.com的客户端设置白名单或者黑名单。
vi /home/nginx/douyu.conf
# 在需要进行访问控制的站点server配置项中,可以针对整个站点或者站点下的某个路径设置访问白名单或黑名单
# 注意:白名单和黑名单注意不要冲突。
# deny 主机地址; # 表示限制指定的主机地址访问当前域名/当前地址, all 表示任意主机
# allow 主机地址; # 表示允许指定的主机地址访问当前域名/当前地址, all 表示任意主机,allow all是nginx的默认值
# 访问控制的使用有2种配置方式,2种配置范围:
# 配置方式1:可以只是用deny,设置访问黑名单。
# 配置方式2:可以使用deny+allow配合,但是allow务必写在deny的前面。
# 配置范围1:可以写在location配置项里面,针对客户端访问的部分路径设置黑名单或白名单。
# 配置范文2:可以写在server配置项里面,针对客户端访问整个站点的黑名单或白名单。
server {
listen 443 ssl;
server_name www.douyu.com;
ssl_certificate /home/nginx/www.douyu.com.crt;
ssl_certificate_key /home/nginx/www.douyu.com.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
root /home/douyu;
index index.html;
}
location /status {
stub_status on;
# 只允许 客户端192.168.233.1访问 /status,其他客户端不能访问
allow 192.168.233.1;
deny all;
}
location /s {
proxy_pass https://www.baidu.com/s;
# 只禁止客户端 192.168.233.151 访问 /s ,其他客户端允许访问。
deny 192.168.233.151;
}
# 写在location外界的访问控制,则表示对整个站点进行白名单和黑名单。
allow all;
deny 192.168.233.153;
}
2 重启nginx服务
注意:访问控制,要么写在server配置项下面表示设置整个站点的访问控制,要么写在地址匹配的location配置项下面,表示设置当前路径的访问控制。
3 在客户机上访问,就会提示403错误
2.3.5.9 自定义错误页面¶
nginx可以让我们根据不同的http响应状态,配置不同的错误页面。
- 修改nginx配置文件
server {
listen 80;
server_name localhost;
location / {
root /home/web/localhost;
index index.html index.htm;
}
location /admin {
# 代理
proxy_pass https://www.douyu.com/; # 代理转发客户端请求到其他站点.
# proxy_pass /main.html; # 代理转发客户端请求到当前站点的其他路径
}
# 配置http错误页面,可以针对一个响应状态,也可以针对多个响应状态,多个响应状态之间必须空格隔开。
error_page 404 /404.html;
error_page 400 401 402 403 /40x.html;
location /404.html {
root /home/douyu/error/;
}
location /40x.html {
root /home/douyu/error/;
}
}
2 在错误日志目录下创建对应的40x.html
添加自定制的错误页面内容(这里我们可以随意在各大网站拷贝一个比较好看的错误页面)
/home/douyu/error/404.html,代码:
/home/douyu/error/40x.html,代码:
3 重启nginx
4 随意访问我们网站里面的一个不存在的页面,就可以看到错误页面
2.3.5.10 nginx的工作模式¶
在nginx的配置文件中,我们可以通过worker_processes配置,设置nginx的工作模式。
nginx的工作模式有2种:单进程模式 与 多进程模式
单进程模式,nginx启动后只有一个主进程(master process)负责提供全部服务,所以有利于排除错误,但是不能发挥nginx的性能,不适用于线上运营。
多进程模式,是目前nginx的默认工作模式,nginx启动后有1个主进程(master process)和至少1个工作进程(worker process),采用多进程来提供服务,可以支撑更多的访问和并发。
worker_processes auto; # 根据当前服务器的物理核数来自动设置工作进程数量,2核2线程,则auto就是4。(推荐)
worker_processes 2; # 不管服务器的CPU是几核几线程的,都按2个工作进程启动。
2.3.5.11 nginx代理服务¶
nginx是一个高性能的代理服务器,不仅可以实现正向代理,也可以实现反向代理。
代理(proxy),就是网络请求转发服务,通常用于在客户端发送请求给服务端时,可能无法直接访问服务端,这时候就需要使用代理服务器了。代理有2种:正向代理与反向代理。
- 正向代理(翻墙、vpn、企业内部与外部的代理转发)。(入域:把自己的电脑配置连接公司内部的局域网)
- 反向代理(用于服务器集群进行对外服务的)
实现反向代理¶
(1) 准备两台机器,这里我直接使用了演示的ubuntu和centos了。
| IP | 用途 | 系统不重要 |
|---|---|---|
| 192.168.233.152 | 代理服务器 | centos |
| 192.168.233.153 | WEB服务器 | ubuntu |
(2) 在代理服务器(centos)上添加配置
进行如下配置:
server {
# listen 80;
# server_name www.douyu.com;
# location / {
# root /home/web/douyu;
# index index.html index.htm;
# }
listen 443 ssl;
server_name www.douyu.com;
ssl_certificate /home/nginx/www.douyu.com.crt;
ssl_certificate_key /home/nginx/www.douyu.com.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# location / {
# root /home/web/douyu;
# index index.html index.htm;
# }
location / {
proxy_pass http://192.168.233.153:8000/;
}
location /status {
stub_status on;
}
}
保存nginx配置并重启nginx
web服务器(ubuntu系统下)安装并启动django项目,把host设置为0.0.0.0,允许外界通过IP访问。
# 因为我们使用的ubuntu作为web服务器,模仿公司的正式运营服务器,所以此处不使用虚拟环境,而是直接安装使用python,可以达到最大化利用服务器资源。
sudo apt install -y python3-pip
# 因为需要让django-admin命令全局可用,所以切换到root用户操作
su root
# 安装django模块
pip install django -i https://pypi.tuna.tsinghua.edu.cn/simple
# 创建一个属于web项目代码的存储目录,并切换进入
mkdir /home/www && cd /home/www
# 基于django-admin.py命令,生成项目
django-admin startproject xianyan
# 切换到项目根目录下
cd xianyan
# 开放防火墙,允许当前项目使用指定的端口对外提供服务
sudo ufw allow 8000/tcp
python manage.py runserver 0.0.0.0:8000 # 此处只是测试,真实的企业中会使用uwsgi或者 gunicron/ uvincron来运行django项目,而不是使用manage.py
(4) 我们访问www.douyu.com,就可以正常访问到ubuntu系统里面启动的项目了。
(5) 反向代理,配置OK。
1台->ab->16C32G(CPU16核32G内存) 服务器->并发数万->
企业站/校园官网/政府官网-> 4C8G10M -> 并发1万( 没有大量的图片/视频 )
电商/论坛/社交 -> 16C32G -> 并发几万
10万并发游戏/视频网站-> 4台服务器(16C32G)-> 10万玩家在线(游戏)
10万并发直播-> 4台服务器(32C46G)-> 10万观众在线(视频)
如何解决并发上万的访问流量,使用什么配置的服务器和架构->C10K(k表示1000)
C100K-> 十万并发/秒 -> 十万并发的网站(应该在业内是小有名气的了,当前城市或许听说过的)-> 100W用户的网站
2.3.5.12 nginx负载均衡¶
负载均衡(load Banlancer): 当单台服务器(单点服务)不能满足用户访问量,此时可以使用多台服务器(服务器集群)进行分担访问压力(一根筷子与一把筷子的故事)
集群的概念: 就是一组服务器干一件事情。
使用服务器集群,有利于提高项目的可用性。
高可用: 如果有一台机器宕机,其他的服务器可以正常提供服务
负载均衡器,有软件和硬件之分的。如果性能要求非常高,使用硬件。常规下软件的负载均衡就可以了。nginx就是一种软件级别的负载均衡。
nginx负载均衡配置¶
(1) 准备3台以上的服务器,其中1台作为负载均衡服务器,2台用作web服务器(上游服务器)
模拟3个服务器的站点内容,同时为了识别,给不同的服务器下提供web站点内容(不同的IP服务器的内容显示不一样)。
| IP | 用途 | 系统不重要 |
|---|---|---|
| 192.168.233.152 | 负载均衡器 | centos,安装nginx |
| 192.168.233.153 | web服务器 | ubuntu,运行python代码 |
| 192.168.233.154 | web服务器 | centos,运行python代码 |
192.168.233.153,ubuntu服务器已经提供了一个django站点。
192.168.233.154,centos,也创建一个django项目。
# 模仿公司的正式运营服务器,所以此处不使用虚拟环境,而是直接安装使用python,可以达到最大化利用服务器资源。
yum install -y python3.11 python3.11-pip && pip3 install setuptools
# 安装django模块
pip3 install django -i https://pypi.tuna.tsinghua.edu.cn/simple
# 创建一个属于web项目代码的存储目录,并切换进入
mkdir /home/www && cd /home/www
# 基于django-admin.py命令,生成项目
django-admin startproject xianyan
# 切换到项目根目录下
cd xianyan
# 开放防火墙,允许当前项目使用指定的端口对外提供服务
# 临时关闭selinux
setenforce 0
# 查看selinux启用状态,Enforcing运行状态,Permissive关闭状态,Disabled禁用状态
getenforce
# 永久关闭selinux
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config
# 设置开放8000端口,并永久生效
firewall-cmd --add-port=8000-8008/tcp --permanent
firewall-cmd --reload # 每次开发/关闭端口或服务,必须更新防火墙规则,否则不生效
# 启动django
python3 manage.py runserver 0.0.0.0:8000
(3) 把192.168.233.152(centos系统)中的nginx配置成负载均衡器,打开nginx配置文件,配置负载均衡
# upstream 变量名 {
# server 服务器IP地址:端口;
# server 服务端IP地址:端口;
# ....
# }
# 定义负载均衡的一组上游服务器。
upstream xianyan_select {
# server IP/域名:端口; 这种格式,表示当前nginx采用的负载均衡策略,是select模式。
# 负载均衡策略,就是用于设置nginx如何把流量分配给组内服务器的。
# select 表示队列轮询,每一台服务器平均分担客户端访问。
server 192.168.233.153:8000; # 一行一个服务器
server 192.168.233.154:8000;
}
server {
listen 443 ssl;
server_name www.douyu.com;
ssl_certificate /home/nginx/www.douyu.com.crt;
ssl_certificate_key /home/nginx/www.douyu.com.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# 反向代理
location / {
proxy_pass http://xianyan_select; # 此处的xianyan是一个变量,是在上面第7行upstream定义的上游服务器组的代表变量。
}
负载均衡的调度策略¶
基于Nginx实现的负载均衡,nginx提供了有5种不同的调度算法(调度策略):
- select,默认算法,轮询算法,每一台服务器都会被平均分配流量。
- ip_hash,IP映射,把客户端IP的hash值与上游服务器进行捆绑,固定的服务器处理固定的IP的客户端请求。
- url_hash,url映射,把客户端请求的url地址的hash值与上游服务器进行捆绑,固定地址访问固定的服务器。
- weight,性能分配,给每一台服务器设置一个权重分数,基于分数进行流量进行分发。【最常用的】
- fair,响应时间分配,根据后台响应时间来分发请求,响应时间短的分发的请求多,响应事件长的分配的请求少。(第三方需要单独编译模块(nginx-upstream-fair)才可用)
修改以下配置(详情看图)
# server {
# listen 80;
# server_name www.douyu.com;
# location / {
# root /home/douyu;
# index index.html;
# }
# location /status {
# stub_status on;
# }
# }
# upstream 变量名 {
# server 服务器IP地址:端口;
# server 服务端IP地址:端口;
# ....
# }
# select 轮询策略
upstream xianyan-select {
server 192.168.233.153:8000 ;
server 192.168.233.154:8000 ;
}
# ip_hash IP哈希映射策略
upstream xianyan-ip-hash {
server 192.168.233.153:8000;
server 192.168.233.154:8000;
server 192.168.233.151:8080;
ip_hash;
}
# url_hash url哈希映射策略
upstream xianyan-url-hash {
server 192.168.233.153:8000;
server 192.168.233.154:8000;
server 192.168.233.151:8080;
hash $request_uri;
}
# weight 性能策略,基于权重值来主观分配
upstream xianyan-weight {
server 192.168.233.153:8000 weight=8 max_fails=2 fail_timeout=30s;
server 192.168.233.154:8000 weight=2 max_fails=2 fail_timeout=30s;
server 192.168.233.151:8080 weight=8 max_fails=2 fail_timeout=30s;
# 优化,开启长链接,300表示5分钟超时
keepalive 300;
}
# fair 响应时间策略(前提是nginx提前安装编译了这个模块)
# upstream xianyan-fair {
# server 192.168.233.153:8000 weight=8 max_fails=2 fail_timeout=30s;
# server 192.168.233.154:8000 weight=2 max_fails=2 fail_timeout=30s;
# server 192.168.233.151:8080 weight=8 max_fails=2 fail_timeout=30s;
# fair;
# }
server {
listen 443 ssl;
server_name www.douyu.com;
ssl_certificate /home/nginx/www.douyu.com.crt;
ssl_certificate_key /home/nginx/www.douyu.com.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# 反向代理
location / {
# proxy_pass http://xianyan-select;
# proxy_pass http://xianyan-ip-hash;
# proxy_pass http://xianyan-url-hash;
proxy_pass http://xianyan-weight;
proxy_pass http://xianyan-fair;
}
# # 代理
# location / {
# proxy_pass http://192.168.233.153:8000/; # 假设这就是我们以后部署Sunday的服务器
# }
# # 代理
# location / {
# # root /home/douyu;
# # index index.html;
# proxy_pass http://127.0.0.1:8000;
# }
# location /status {
# stub_status on;
# allow 192.168.233.1;
# deny all;
# }
# location /s {
# proxy_pass https://www.baidu.com/s;
# deny 192.168.233.151;
# }
error_page 404 /404.html;
location /404.html {
root /home/douyu/error;
}
error_page 501 502 /5x.html;
location /5x.html {
root /home/douyu/error;
}
}
参考图片,里面的IP地址和变量有所不同。
(4)centos,重启nginx服务。
(5) 不断刷新并访问http://www.huya.com,就可以看到访问的页面是不同的页面
3. 容器化技术¶
3.1 基本概念¶
虚拟化技术就是针对计算机的剩余资源(基于操作系统本身的 CPU、内存、网卡、硬盘的资源)进行再次系统封装,提供一个不依赖于硬件的管理技术。我们使用的vmware虚拟机就是虚拟化技术的一种。容器化技术属于虚拟化技术的一种。
首先对比容器化与传统Vmware这些虚拟机在搭建操作系统或者项目环境时的特性差异。
目前比较常用的容器化技术主要是docker,但是除了docker以外,还有另一个容器化技术:podman。
podman的出现是为了替代docker,类似mariaDB替代mysql的情况。所以podman在使用上和docker是一模一样的。
docker基本概述¶
Docker是一款Golang语言开发的开源的应用容器引擎,可以将应用程序(例如:我们写的django代码或者我们要安装的nginx,python,mysql等)及其所有依赖环境(python模块,python解析器或者nginx的运行环境、mysql的运行环境)打包到一个独立的、可移植的容器(就是一个独立的整体)中。这些容器可以在任何支持 Docker 的环境中运行,无论是开发、测试还是生产环境,从而提供了许多应用场景和优势。
为什么要使用docker¶
- 轻量级和快速:Docker 容器是轻量级的,与传统的虚拟机相比,启动和停止容器的速度更快。这使得应用程序可以更快地部署、扩展和更新。
- 环境一致性:Docker 可以确保应用程序在不同环境中具有一致的运行方式,包括开发、测试和生产环境。容器化应用程序可以打包所有依赖项,并在任何支持 Docker 的环境中运行,避免了由于环境差异导致的问题。
- 高度可移植性:Docker 容器可以在不同的操作系统和云平台上运行,提供了高度的可移植性。这意味着你可以在本地开发和测试容器化的应用程序,然后将其轻松地部署到云端或其他服务器上。
- 快速部署和扩展:使用 Docker,你可以快速部署和扩展应用程序。通过创建容器镜像,你可以将应用程序及其所有依赖项打包到一个独立的、可移植的单元中。当需要增加应用程序的实例数量时,只需简单地复制容器即可。
- 简化依赖管理:Docker 可以帮助简化应用程序的依赖管理。通过将应用程序及其依赖项打包到容器中,你可以避免由于不同版本的软件包之间的冲突而导致的问题。每个容器都有自己的运行时环境,可以独立地管理和更新依赖项。
- 安全性和隔离性:Docker 提供了一定程度的安全性和隔离性。每个容器都运行在自己的独立环境中,互相之间不会产生冲突。此外,Docker 还提供了一些安全功能,如命名空间和控制组,可以限制容器的资源使用和访问权限。
应用场景¶
- 应用程序的快速部署和交付:使用 Docker 可以将应用程序及其依赖项打包成一个镜像,然后在不同的环境中快速部署和交付。这样可以避免由于系统环境差异导致的部署问题,加快应用程序的交付速度。
- 多租户环境隔离:在共享的服务器上运行多个应用程序时,使用 Docker 可以实现应用程序之间的隔离。每个应用程序都可以运行在自己的容器中,互相之间不会产生冲突,提高了安全性和稳定性。
- 开发和测试环境的一致性:使用 Docker 可以创建与生产环境完全一致的开发和测试环境。开发人员可以在本地使用 Docker 运行应用程序,而不需要担心环境差异导致的问题。同时,测试团队也可以使用相同的容器镜像进行测试,确保测试环境和生产环境的一致性。
- 弹性扩展和负载均衡:Docker 可以很方便地实现应用程序的弹性扩展和负载均衡。通过在多个主机上运行多个容器实例,可以根据负载情况自动调整容器数量,并通过负载均衡器将请求分发到不同的容器中,提高应用程序的性能和可用性。
- 微服务架构:Docker 可以很好地支持微服务架构。每个微服务可以打包成一个独立的容器,通过容器之间的网络通信进行交互。这样可以实现每个微服务的独立部署、扩展和管理,提高系统的灵活性和可维护性。
3.2 Docker安装¶
Mac/Windows需要下载安装docker-desktop:
# docker-desktop的运行依赖于hyperV
# Vmware默认和hyperV冲突的。所以需要在windows的终端下调整hyperV的开启模式
bcdedit /set hypervisorlaunchtype auto
Centos安装docker-ce(社区版)
# 安装下载工具
yum install -y yum-utils
# 设置源仓库
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 安装docker以及相关的组件
yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
ubuntu安装docker-ce(社区版)
# 更新源
sudo apt-get update
# 安装curl命令以及curl支持https的组件工具
sudo apt-get install -y ca-certificates curl gnupg
# 创建目录并分配权限
sudo install -m 0755 -d /etc/apt/keyrings
# 设置远程仓库的秘钥(证书)
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# 设置源
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 更新源
sudo apt-get update
# 安装docker-ce
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
不管是centos还是ubuntu,确认是否安装完成。可以使用以下命令来确认:
Linux下启动或关闭Docker
centos安装docker以后是没有启动的。
| systemctl start docker | 启动docker |
| systemctl stop docker | 停止docker |
| systemctl restart docker | 重启docker |
使用docker之前,必须清楚2个概念:镜像(image)和容器(contariner)。
镜像是构建和运行容器的打包文件,容器是镜像运行在docker平台的软件和依赖环境(包含了计算机资源)。
vmware的镜像和docker的镜像:vmware的系统镜像打包文件格式一般是:iso,而docker的镜像打包文件格式一般是:tar.gz
vmware提供的镜像可以用于创建多个容器,但是vmware的容器只能是操作系统。docker的镜像也可以用于创建多个容器,但是docker的容器不仅可以是操作系统还是软件环境。
3.3 Docker命令¶
| 命令 | 描述 |
|---|---|
docker version |
查看docker的版本信息(客户端与服务端版本都显示) |
docker infodocker systeminfo |
查看docker的系统信息,也包含了版本信息 |
| docker system df | docker磁盘使用数据 |
docker logindocker login -u <账号> -p <密码> <镜像仓库地址> |
登录docker镜像仓库, 镜像仓库地址不指定则默认为官方仓库DockerHub |
docker logoutdocker logout <镜像仓库地址> |
登出docker镜像仓库, 镜像仓库地址不指定则默认为官方仓库DockerHub |
docker push <镜像名:镜像版本> <镜像仓库地址> |
推送镜像到指定的镜像仓库 镜像仓库地址不指定则默认为官方仓库DockerHub 推送时,如果是推送到官方仓库,则需要设置token |
docker search <关键字> |
按关键字搜索镜像 按条件搜索镜像: docker search --filter=STARS=150 chrome |
docker image ls --alldocker image lsdocker images docker images --all |
列出所有镜像 |
docker image pull <镜像名:版本号>docker pull \<镜像名:版本号> |
拉取镜像 如果不指定版本号,默认拉取最新版本的镜像 |
docker image rm <镜像名/镜像ID>docker rmi \<镜像名:版本号/镜像ID> |
删除镜像 如当前镜像文件的容器在运行,要先删容器后删除镜像 |
| docker image prune | 删除没有使用的镜像 |
| docker save -o \<镜像名-版本号.tar.gz> \<镜像名:版本号> | 打包镜像 把docker中的镜像打包成文件用于发送他人或备份 |
| docker load -i \<镜像名-版本号.tar.gz> | 加载镜像 把镜像文件解包并加载到当前系统安装的docker平台中 |
| docker build -t \<镜像名:版本号> . | 创建镜像 使用Dockerfile配置文件的指令创建定制镜像, .表示Dockerfile文件所在目录,自己根据实际情况填写 |
| docker run \<参数选项> \<镜像名:版本号> \<第一条命令> | 创建容器 需指定镜像名,并设置容器启动后执行的第一条命令 参数选项: -t 表示容器启动后会进入其命令行终端 -i 表示以“交互模式”运行容器 --name 表示设置容器的名称 -d 创建一个守护式容器在后台运行 -p 端口映射,格式: 外部端口:容器端口-v 目录映射,格式: 外部目录:容器目录-e 设置环境变量,格式: 变量名=变量值--privileged 容器内是否使用真正的 root 权限 --restart=always 设置容器退出时是否重启 |
docker container lsdocker container ls --alldocker ps docker ps --all |
列出容器 容器的运行状态: 运行中 Up 停止运行 Exit 不断重启 Creating |
docker container start <容器名/容器ID>docker container start <容器名/容器ID> <容器名/容器ID> ...docker start <容器名/容器ID> docker start <容器名/容器ID> <容器名/容器ID> ... |
启动容器 可以同时启动多个容器,容器之间使用空格隔开 |
docker container stop <容器名/容器ID>docker container stop <容器名/容器ID> <容器名/容器ID> ...docker stop <容器名/容器ID> docker stop <容器名/容器ID> <容器名/容器ID> ... |
停止容器 可以同时停止多个容器,容器之间使用空格隔开 |
docker container restart <容器名/容器ID>docker container restart <容器名/容器ID> <容器名/容器ID> ...docker restart <容器名/容器ID> docker restart <容器名/容器ID> <容器名/容器ID> ... |
重启容器 可以同时重启多个容器,容器之间使用空格隔开 |
docker container kill <容器名/容器ID>docker container kill <容器名/容器ID> <容器名/容器ID> ...docker kill <容器名/容器ID> docker kill <容器名/容器ID> <容器名/容器ID> ... |
杀死容器 在容器无法通过stop命令停止时使用 |
docker container rm <容器名/容器ID>docker container rm <容器名/容器ID> <容器名/容器ID> ...docker rm <容器名/容器ID> docker rm <容器名/容器ID> <容器名/容器ID> ... |
删除容器 删除所有容器: docker rm -f $(docker ps -aq) |
docker container exec -it <容器名/容器ID> <第一个命令>docker exec -it <容器名/容器ID> <第一个命令> |
进入容器 只能进入处于启动状态的容器,这种情况第一个命令一般是 bash |
| docker commit \<容器名:/容器ID> \<新镜像名:自定义版本号> | 打包容器 也可以理解为基于容器现有的内容创建新镜像, 把当前容器运行的一切内容保存成镜像文件 |
| docker cp \<容器名/容器ID:容器内部路径> \<容器外部路径> | 把容器文件复制到容器外部 |
| docker cp \<容器外部路径> \<容器名/容器ID:容器内部路径> | 把外部文件复制到容器里面 |
docker container update --restart=always <容器名/容器ID>**docker update --restart=always <容器名/容器ID> ** |
修改容器在run启动时配置,如把容器设置为开机自启。 |
| docker logs -f --tail=日志数量 <容器名/容器ID> | 实时监控指定容器的运行日志 |
docker container statsdocker stats |
实时监控容器的资源使用统计信息 |
docker port <容器名/容器ID> |
查看指定容器的端口映射情况 |
3.3.1 镜像管理¶
拉取镜像¶
# docker pull <镜像名:镜像版本号>
docker pull nginx
docker pull nginx:1.25.3
docker pull mysql
docker pull redis
列出镜像¶
删除镜像¶
当镜像被引用创建容器时,是无法被删除的。
[root@moluo ~]# docker rmi redis
Error response from daemon: conflict: unable to remove repository reference "redis" (must force) - container 78e82690fc04 is using its referenced image 961dda256baa
这时候需要先删除容器再删除镜像。
打包镜像¶
把docker管理的镜像进行打包成文件,一般用于发送镜像给别人或者备份该镜像。
加载镜像¶
把已经打包成压缩包文件的镜像加载到docker平台里
# docker load -i <镜像包名文件路径.tar.gz>
# 例如,我们先删除本地的mysql镜像,然后把本地之前打包的镜像,导入到docker中。
docker rmi mysql
docker images
docker load -i mysql_lastest.tar.gz
docker images
3.3.2 容器管理¶
3.3.2.1 创建容器¶
例1:使用nginx镜像创建一个nginx1容器,并提供外部80端口指向容器内部的80端口。
例2:使用ubuntu镜像,创建一个名为ubuntu1的容器,非后台运行的,启动以后直接进入ubuntu终端了。
例3:使用mysql镜像,创建一个名为mysql1,并且在后台运行的容器,需要设置登陆密码
# -e 设置环境变量,提供给容器内部的软件使用的。
# -e MYSQL_ROOT_PASSWORD=密码 表示设置root用户的密码
# -e MYSQL_DATABASE=数据库 表示让mysql容器创建一个新的数据库
# - e MYSQL_USER=用户名 表示让mysql创建一个新的用户账号
# - e MYSQL_PASSWORD=密码 表示让mysql给新的用户账号设置登陆密码
docker run --name mysql1 -e MYSQL_ROOT_PASSWORD=sunday -d mysql
# -v 设置目录映射
# -v /mysql/data:/var/lib/mysql 表示/mysql/data 是容器外部的目录地址,/var/lib/mysql是容器的目录地址,两个目录形成软链接的关系
# /var/lib/mysql 是官方提供的mysql镜像中默认保存数据文件的默认目录
# /etc/mysql/conf.d 是官方提供的mysql镜像中默认保存配置文件的目录
# /etc/mysql/my.cnf 是官方提供的mysql镜像中默认的配置文件
docker run --name mysql2 -v /mysql/data:/var/lib/mysql -v /mysql/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=sunday -d mysql
例3:使用redis镜像,创建一个名为redis1,并且在后台运行的容器,对外端口是6370,需要指定配置文件
3.3.2.2 列出容器¶
关于查看容器列表中各项数据
| CONTAINER ID | IMAGE | COMMAND | CREATED | STATUS | PORTS | NAMES |
|---|---|---|---|---|---|---|
| 容器的唯一ID | 当前容器所使用的镜像以及镜像版本号 | 启动容器以后运行的首个命令 | 容器的创建时间 | 容器的运行状态 | 容器各个程序锁使用的端口, 有->箭头符号的表示 允许外界通过端口映射访问到容器内部, 没有则需要连接/进入容器内部才能操作 |
容器的唯一别名 |
| 63b841ebaf38 | redis | "docker-entrypoint.s…" | 5 minutes ago | Exited (0) 5 minutes ago 退出状态 |
0.0.0.0:6370->6379/tcp, :::6370->6379/tcp | flamboyant_bassi |
| 047a2b660c13 | ubuntu:22.04 | "bash" | 2 hours ago | Up 2 hours 启动状态 |
0.0.0.0:80->80/tcp, :::80->80/tcp | angry_moore |
| f43e014640ef | mysql | "/docker-entrypoint.…" | 29 minutes ago | Creating (0) 5 seconds age 不断重启状态 |
3306/tcp, 33060/tcp | redis2 |
3.3.2.3 启动、关闭或杀死、删除容器¶
这两个命令不一定有效,配置有问题的容器可能启动会失败,运行中处于死机状态的容器也可能无法关闭。
# 启动1个容器
docker start <容器ID/容器别名>
# 启动多个容器
docker start <容器ID/容器别名> <容器ID/容器别名> <容器ID/容器别名> <容器ID/容器别名>
# 关闭一个容器
docker stop <容器ID/容器别名>
# 关闭多个容器
docker stop <容器ID/容器别名> <容器ID/容器别名> <容器ID/容器别名> <容器ID/容器别名>
# 杀死一个容器
docker kill <容器ID/容器别名>
# 杀死多个容器
docker kill <容器ID/容器别名> <容器ID/容器别名> <容器ID/容器别名> <容器ID/容器别名>
# 删除一个容器(容器必须处于关闭状态才能删除)
docker rm <容器ID/容器别名>
# 删除多个容器(容器必须处于关闭状态才能删除)
docker rm <容器ID/容器别名> <容器ID/容器别名> <容器ID/容器别名> <容器ID/容器别名>
3.3.2.4 进入容器¶
# docker exec -it <容器ID/容器别名> 进入容器后的第一个命令
# 例如,进入redis容器内部操作,进入容器的第一个命令是打开redis-cli客户端
docker exec -it redis1 redis-cli
# 例如,进入mysql容器内部操作,进入容器的第一个命令是打开mysql的交互终端
docker exec -it mysql1 mysql -uroot -p
# 要容器,使用exit即可。
监控容器¶
效果如下:
| CONTAINER ID | NAME | CPU % | MEM USAGE / LIMIT | MEM % | NET I/O | BLOCK I/O | PIDS |
|---|---|---|---|---|---|---|---|
| 容器唯一ID | 容器唯一别名 | CPU使用占比 | 内存使用数值/容器可用最大内存 | 内存使用占比 | 网路I/O的数据量 | 阻塞I/O的数据量 | docker管理的容器进程ID |
| 047a2b660c13 | redis1 | 0.20% | 16.82MiB / 3.548GiB | 0.46% | 1.07kB / 0B | 24.7MB / 24.6kB | 6 |
3.3.2.5 文件复制¶
# 从容器内部复制文件到外部
docker cp <容器名:源文件路径> <新文件路径>
# 例如,我们把redis的数据快照 dump.rdb 从容器内部复制出来
docker cp redis1:/data/ ./
# 从外部复制文件到容器内部
docker cp <源文件路径> <容器名:新文件路径>
# 例如,我们把之前备份的dump.rdb快照文件 还原到新的容器。
docker cp ./data redis1:/
官方提供的镜像的镜像名:library/镜像名或镜像名,而第三方开发者所提供的镜像的镜像名:用户名/镜像名。
3.4 Dockerfile¶
docker/podman中, 镜像是容器的基础,每次执行docker run的时候都会指定哪个基本镜像作为容器运行的基础。我们之前的docker的操作都是使用来自dockerhub提供的官方镜像,直接使用这些镜像只能满足一定的基本需求,当基础镜像无法满足我们的业务需求时,就得使用Dockerfile自己定制这些镜像了。
Dockerfile就是一个描述构建镜像的步骤的文本配置文件,也可以理解是构建自定义镜像过程中的命令集合。
命令集合:Dockerfile指令+Linux Shell命令。
Dockerfile是提供开发者用于定制自定义镜像的配置文件。所以我们需要掌握Dockerfile文件的基本语法。
镜像的定制就类似小时候学画画的水彩画一样,水彩画是一层一层的涂抹上去的,而镜像的定制则是编写定制每一层所添加的配置、文件等命令信息。如果可以把每一层修改、安装、构建、操作的命令都写入到一个脚本,用脚本来构建、定制镜像,这个脚本就是Dockerfile。
Dockerfile 是一个文本文件,其内包含了一条条用于自定义镜像的指令(Instruction),这些指令每一条就构建一层,因此每一条指令的内容,就是告诉docker该如何构建每一层的镜像内容。
注意:Dockerfile中的命令层级如果越多,则构建生成的镜像就越大,也就越臃肿,所以我们应该在学习完Dockerfile的语法以后,尽量采用最少的指令(也就是最少的层级)来自定义构建镜像。
3.4.1 Dockerfile提供的指令¶
| 指令 | 描述 |
|---|---|
| FROM | 设置当前镜像的基础镜像(它的妈妈是谁?相当于执行一次docker pull) |
MAINTAINER |
设置当前镜像的作者信息(告诉使用者,谁创造了它) |
LABEL |
设置当前镜像的作者信息(告诉使用者,谁创造了它) |
| RUN | 设置当前镜像需要完成的shell命令(你希望对FROM拉取回来的镜像进行怎么样的加工?) |
| ADD | 设置从外界复制文件/目录到当前镜像内部,ADD指令会自动解压压缩包,当使用ADD从镜像外界复制压缩包到镜像内部,Docker会自动解压 |
| COPY | 设置从外界复制文件/目录到当前镜像内部,COPY指令不会解压压缩包,当使用COPY从镜像外界复制压缩包到镜像内部,Docker不会自动解压,此时需要额外使用RUN+解压缩命令进行解压,当然也可以不解压。 |
| WORKDIR | 设置当前镜像启动以后的容器的初始工作目录(相当于cd) |
| ENV | 设置当前镜像启动以后的容器的环境变量(相当于 docker -e) |
| VOLUME | 设置当前镜像启动以后的挂载目录(相当于-v参数,指定容器内部提供哪些路径与容器外面进行映射) |
| EXPOSE | 设置当前镜像启动以后的开放端口(相当于-p参数,指定容器内部提供哪些端口与容器外界进行映射) |
| CMD | 设置当前镜像启动以后的首个运行命令(相当于docker run的最后一个参数) |
FROM指令¶
指定基础镜像,制作base image(基础镜像),尽量使用官方的image作为base image。
一个Dockerfile,只能设置一次FROM指令,而其他指令则可以出现多次。
# 不指定基础镜像的版本,默认拉取最新版本
FROM elasticsearch
FROM centos
# 也可以通过英文冒号,设置拉取的镜像版本,注意:镜像名与版本号之间不要有空格!!!
FROM ubuntu:20.04
FROM python:3.9
MAINTAINER指令¶
容器元信息,作者或帮助信息,类似于代码注释,表名当前镜像的制作作者是谁?怎么联系?
也可以采用LABEL指令来设置,LABEL是一个更灵活的版本,可以替代MAINTAINER,LABEL可以设置任何需要设置的元数据,并且可以使用docker inspect命令轻松查看label信息。
LABEL version="1.0.0"
LABEL author="moluo"
LABEL maintainer="649641514@qq.com"
MAINTAINER EMAIL "649641514@qq.com"
RUN指令¶
设置基于基础镜像的上层,进行命令的加工,是一个万能指令,用于让镜像执行shell命令的。
对于RUN执行复杂的shell命令,避免无用的分层,多条shell命令用\换行或&& ,把多个shell命令合成一条shell命令!
不好的写法:
FROM python:3.9
RUN yum update && yum install -y vim \
Python-dev && /bin/bash -c "source $HOME/.bashrc;echo $HOME"
WORKDIR /usr/local/src
RUN wget xxxxx # 下载的文件不会被保存到/usr/local/src,而是可能保存到用户家目录下,两次RUN的命令是2层压缩包来的,相互独立
推荐的写法:
FROM python:3.9
RUN yum update \
&& yum install -y vim Python-dev \
&& source $HOME/.bashrc;echo $HOME \
&& cd /usr/local/src \
&& wget xxxxx
WORKDIR指令¶
相当于linux的cd命令,用于切换容器执行shell的工作目录,务必使用绝对路径!不要用RUN cd
ADD指令¶
复制解压,把容器外界(宿主机)的一个文件/目录/压缩包,复制到容器内指定路径下,相当于 docker cp加强版。
# ADD 容器外部文件/目录/压缩包 容器内部
ADD /opt/python3.9.9.tar.gz /opt/ # 这里,ADD会自动把tar.gz进行解压,最终容器内部会得到一个目录 Python3.9.9
ADD requirements.txt /opt/ # 这里,ADD命令会尝试对文件requirements.txt进行解压缩,如果不能,则直接复制到/opt目录下
ADD requirements.txt /opt/r.txt # 这里,ADD命令会尝试对文件requirements.txt进行解压缩,如果不能,则直接复制并改名为/opt/r.txt
COPY指令¶
复制把容器外界(宿主机)的一个文件/目录,复制到容器内指定路径下,相当于 docker cp。
COPY指令只是单纯的把容器外界(宿主机)的文件/目录, 拷贝到容器内,但是没有解压缩的命令,所以对于非压缩包文件的复制尽量使用COPY指令,而不要使用ADD指令。
COPY requirements.txt /opt/ # 这里,COPY命令直接复制到/opt目录下,不改名
COPY requirements.txt /opt/r.txt # 这里,COPY命令直接复制并改名为/opt/r.txt
注意:
如果要添加一个远程文件/目录或压缩包,尽量先下载到容器外界的宿主机里面,接着使用ADD或COPY复制到容器内部。
如果上面的步骤不行,则可以使用RUN curl或RUN wget来操作,但是这样会导致镜像冗余。
ENV指令¶
设置镜像启动以后的容器内部的环境变量。
ENV MYSQL_ROOT_PASSWORD 123456
ENV REDIS_DEFAULT_PASSWORD 123456
# 如果在dockerfile其他的指令里面需要使用ENV设置的环境变量则必须保证环境设置的指令在上方
ENV MYSQL_VERSION 8.0.30
RUN yum install -y mysql-server="${MYSQL_VERSION}"
VOLUME指令¶
设置镜像启动以后容器内部可以与外界进行目录映射的路径。相当于指定将来docker启动以后的-v参数。
EXPOSE指令¶
设置镜像启动以后容器内部对外开放的端口。相当于指定将来docker启动以后的-p参数。
CMD指令¶
用于Dockerfile的结尾运行命令,类似RUN,区别在于参数值是一个数组/列表,按空格隔开。
使用 Dockerfile之前,先切换成国内docker镜像源
配置docker镜像加速:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
mkdir -p /etc/docker
vi /etc/docker/daemon.json
{
"registry-mirrors" : [
"https://docker.mirrors.ustc.edu.cn",
"http://hub-mirror.c.163.com",
"https://2xdmrl8d.mirror.aliyuncs.com"
]
}
# 保存上面的配置
sudo systemctl daemon-reload
sudo systemctl restart docker
3.4.2 Dockerfile封装Django镜像¶
方案1:Dockerfile中通过网络拉取所有需要构建的资源¶
Dockerfile,代码:
FROM python:3.11
LABEL author=moluo
LABEL date=2023/11/23
LABEL version=1.0.0
LABEL email=649641514@qq.com
RUN apt-get update \
&& apt-get install -y python3-pip \
&& pip3 install django -i https://pypi.tuna.tsinghua.edu.cn/simple \
&& mkdir -p /home/www/xianyan
WORKDIR /home/www/xianyan
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
在Dockerfile所在目录下执行构建命令:
效果:
方案2:提前准备源码包复制到镜像内部进行构建¶
在/home下建立了docker目录,在这个目录下准备好要构建镜像的文件和源码包。
目录结构:
终端执行如下命令:
mkdir /home/docker && cd /home/docker
# 下载一个django-4.0.7的源码包
wget -O Django-4.2.7.tar.gz https://gitee.com/mirrors/django/repository/archive/4.2.7?format=tar.gz
# 拉取基础镜像到本地
docke pull python:3.11
编写Dockerfile构建镜像的配置文件
Dockerfile,代码:
FROM python:3.11
LABEL version="4.2.7"
LABEL maintainer="649641514@qq.com"
ADD Django-4.2.7.tar.gz /usr/local/src
RUN cd /usr/local/src \
&& mv django-4.2.7 django \
&& cd django \
&& python3 setup.py install
WORKDIR /home
COPY run.sh /home/run.sh
RUN django-admin startproject xianyan \
&& cd xianyan \
&& sed -i "s/ALLOWED_HOSTS = \[\]/ALLOWED_HOSTS = \['\*'\]/g" /home/xianyan/xianyan/settings.py \
&& mv /home/run.sh /home/xianyan/run.sh \
&& chmod 755 run.sh
WORKDIR /home/xianyan/
EXPOSE 8000
CMD ["/bin/sh", "/home/xianyan/run.sh"]
注意:Dockerfile中不能出现命令以外的任何注释。以下是注释版本:
# 指定当前定制镜像的基础镜像以及版本号
FROM python:3.11
# 指定镜像的描述信息[版本号、作者]
LABEL version="4.2.7"
LABEL maintainer="649641514@qq.com"
# 从镜像外复制并解压相关文件到镜像内部
ADD Django-4.2.7.tar.gz /usr/local/src
# 运行终端命令,安装django到python解析器里面
RUN cd /usr/local/src \
&& mv django-4.2.7 django \
&& cd django \
&& python3 setup.py install
# 切换工作目录
WORKDIR /home
# 复制外部文件到容器内部执行目录,run.sh肯定我们自己编写的一个shell脚本,这里是用于启动django项目的shell命令
COPY run.sh /home/run.sh
# 创建一个django项目,并切换目录到django项目根目录下,并替换settings的内容,然后复制run.sh运行脚本到项目根目录下,设置权限
RUN django-admin startproject xianyan \
&& cd xianyan \
&& sed -i "s/ALLOWED_HOSTS = \[\]/ALLOWED_HOSTS = \['\*'\]/g" /home/xianyan/xianyan/settings.py \
&& mv /home/run.sh /home/xianyan/run.sh \
&& chmod 755 run.sh
# 切换工作目录
WORKDIR /home/xianyan/
# 开放镜像的端口8000
EXPOSE 8000
# CMD就是RUN,用于在结尾执行终端命令
CMD ["/bin/sh", "/home/xianyan/run.sh"]
编写run.sh
Docker构建镜像
构建完成后,可以看到生成一个新镜像。
启动镜像,并把8000端口映射到物理机的8000端口。
docker run -d -p 8000:8000 --name=django1 mydjango:4.2.7
docker ps
# 如果无法运行,则可以通过以下命令查看错误
docker logs django1
# 查看镜像的相关信息
docker inspect django:4.2.7
完成操作以后,要关闭容器,可以使用以下命令:
3.5 Docker-Compose¶
在上面的学习中,我们已经学会了使用一个Dockerfile配置文件,可以定义构建一个自定义docker镜像。在工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要运行一个django项目,除了django服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。此时我们就需要同时操作多个不同功能的容器了,开发中遇到这种情况,一般使用容器编排技术来完成一组容器的配置和管理,让一组容器配合运行一个项目或者完成一个任务。
容器编排技术有很多,其中最著名的就是Kubernetes(因为首尾字母中间有8个字母,所以简称k8s)了。而开发中除了k8s以外,还有docker compose 与 docker swarm是较为常用的,当时这两个往往是用于本地开发或者企业内部的测试环境中。但是如果公司使用了k8s,基本不会使用docker compose 与 docker swarm,因为k8s强大无比,当然功能强大就意味着k8s入门门槛相对与docker compose 或者 docker swarm 要高,主要是k8s默认使用分布式集群架构的。
注意
podman与docker都一样属于容器平台,里面的容器是共用的,但是docker-compose的运行依赖于docker,而如果当前操作系统安装的是podman,则需要使用podman-compose来操作。
当然,podman-compose和docker-compose的使用和语法是一样的。
Docker-Compose项目是Docker官方的开源项目,负责实现对Docker容器集群的快速编排和批量管理。Docker-Composev1项目由Python编写(所以必须保证当前系统安装了python),Docker-Composev2项目改用了Golang语言编写(不需要准备Go语言的运行环境)。调用Docker服务提供的API来对容器进行批量的管理和编排。因此只要所操作的平台支持Docker API,就可以在其上利用Docker-Compose来进行Docker容器的批量编排和批量管理。
Docker-Compose会将需要管理的Docker容器分为三层,分别是工程(project),服务(service)以及容器(container)。
Docker-Compose允许我们开发者通过一个单独的docker-compose.yml配置文件(YAML 格式)来定义一组相关联的docker容器为一个工程(project)。一个工程至少有一个服务,一个服务下至少有一个容器。
Docker-Compose运行指定目录下的所有关联文件组成一个工程(工程名默认为当前目录名)。一个工程当中可包含多个服务,每个服务中可以定义Docker容器运行的镜像,参数,环境变量等依赖信息。
Docker-Compose的工程配置文件默认为docker-compose.yml,也可以通过 -f 参数来指定成其他的配置文件名。
3.5.1 安装与卸载¶
安装环境查看
# 查看系统类型
uname -s
# CPU的内核架构,x86 x86_64
uname -m
# Linux的发行版本
uname -a
# Linux的发行版本(详尽)
lsb_release -a # CentOS: yum install -y redhat-lsb
安装地址:https://docs.docker.com/compose/install/
# https://github.com/docker/compose/releases/download/v2.23.1/docker-compose-linux-x86_64
curl -L "https://github.com/docker/compose/releases/download/v2.23.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
查看安装的版本
卸载¶
3.5.2 常用命令¶
docker-compose的操作方式,主要是通过终端命令+docker-compose.yml编排配置文件组合使用的。其中终端命令,实际上就是docker命令的增强版。因为docker提供的终端命令一般用于操作操作单个容器,而docker-compose提供的终端命令,可以多个容器组成一个整体服务容器组,批量执行。
基本命令格式
命令选项如下
-f 指定Compose配置文件,默认为当前目录下docker-compose.yml,也可以使用-f的全拼:--file
# -p --project-name NAME 指定项目名称,默认使用当前所在目录为项目名
# --verbose 输出更多调试信息
# -v,-version 打印版本并退出
--log-level LEVEL 定义日志等级(DEBUG, INFO, WARNING, ERROR, CRITICAL)
docker-compose up¶
根据容器编排配置文件docker-compose.yml,进行编排和启动容器。相当于docker pull和docker run 、docker build的组合增强版本。
docker-compose up [options] [--scale SERVICE=NUM...] [SERVICE...]
选项包括:
-f 指定compose模板文件名
-d 在后台守护进程的方式运行docker容器
# 常用写法:
# docker-compose up
# docker-compose up -d
# docker-compose -f docker-compose.yml up -d
docker-compose down¶
停止运行并删除docker-compose.yml配置的容器(contariner)、网络(network)、逻辑卷(volume)。相当于docker stop 和docker rm的组合增强版。
docker-compose down [options]
选项包括:
-f 指定compose模板文件名
# 常用写法:
# docker-compose down
# docker-compose -f docker-compose.yml down
docker-compose stop¶
停止运行docker-compose.yml配置的容器,相当于docker stop的增强版,将来可以通过docker-compose start 再次批量启动容器
docker-compose stop [options] [SERVICE...]
选项包括:
-f 指定compose模板文件名
# 常用写法:
# docker-compose stop
# docker-compose -f docker-compose.yml stop
docker-compose start¶
启动运行docker-compose.yml配置的容器,相当于docker start的增强版,可以通过docker-compose stop 关闭运行。
docker-compose start [SERVICE...]
选项包括:
-f 指定compose模板文件名
# 常用写法:
# docker-compose start
# docker-compose -f docker-compose.yml start
docker-compose ps¶
列出当前工程项目中的所有服务容器,相当于docker ps的增强版
docker-compose ps [options] [SERVICE...]
# 常用写法:
# docker-compose ps
# docker-compose -f docker-compose.yml ps
docker-compose logs¶
列出当前工程项目中运行容器过程中的运行日志,相当于docker logs的增强版。
docker-compose logs [options] [SERVICE...]
选项包括:
-f 跟踪日志输出
# 常用写法:
# docker-compose -f docker-compose-mysql.yml logs # 查看当前docker-compose.yml中所有容器的运行日志,列出所有日志以后,指令执行完成
# docker-compose -f docker-compose-mysql.yml logs -f # 监控当前docker-compose.yml中所有容器的运行日志,列出所有日志以后,会阻塞终端继续等待日志输出。
docker-compose bulid¶
按docker-compose.yml中配置的自定义模板Dockerfile来进行批量编译自定义容器,相当于docker build的增强版。
docker-compose build [options] [--build-arg key=val...] [SERVICE...]
构建(重新构建)项目中的服务容器。
选项包括:
–compress 通过gzip压缩构建上下环境
–force-rm 删除构建过程中的临时容器
–no-cache 构建镜像过程中不使用缓存
–pull 始终尝试通过拉取操作来获取更新版本的镜像
-m, –memory MEM为构建的容器设置内存大小
–build-arg key=val为服务设置build-time变量
服务容器一旦构建后,将会带上一个标记名。可以随时在项目目录下运行docker-compose build来重新构建服务
docker-compose pull¶
按docker-compose.yml的配置需求,拉取镜像文件。相当于docker pull的增强版。
docker-compose pull [options] [SERVICE...]
拉取服务依赖的镜像。
选项包括:
–ignore-pull-failures,忽略拉取镜像过程中的错误
–parallel,多个镜像同时拉取
–quiet,拉取镜像过程中不打印进度信息
docker-compose pull
拉取服务依赖的镜像
docker-compose restart¶
批量重启容器,相当于docker stop 和 docker start的增强版。
docker-compose restart [options] [SERVICE...]
重启项目中的服务。
选项包括:
-t, –timeout TIMEOUT,指定重启前停止容器的超时(默认为10秒)
docker-compose restart
重启项目中的服务
docker-compose rm¶
批量删除容器,前提是所有容器已经被关闭了。相当于docker rm的增强版。
docker-compose rm [options] [SERVICE...]
删除所有(停止状态的)服务容器。
选项包括:
–f, –force,强制直接删除,包括非停止状态的容器
-v,删除容器所挂载的数据卷
docker-compose rm
删除所有(停止状态的)服务容器。推荐先执行docker-compose stop命令来停止容器。
docker-compose run¶
批量创建容器,相当于docker run的增强版。
docker-compose run [options] [-v VOLUME...] [-p PORT...] [-e KEY=VAL...] SERVICE [COMMAND] [ARGS...]
在指定服务上执行一个命令。
docker-compose run ubuntu ping www.baidu.com
在指定容器上执行一个ping命令。
docker-compose scale¶
根据docker-compose.yml配置文件,指定服务运行的容器的数量。相当于docker scale的增强版。
docker-compose pause¶
批量暂停容器,相当于docker pause的增强版。
docker-compose uppause¶
批量恢复暂停的容器,相当于docker uppause的增强版。
docker-compose kill¶
批量杀死容器,相当于docker kill的增强版。
docker-compose kill [options] [SERVICE...]
通过发送SIGKILL信号来强制停止服务容器。
支持通过-s参数来指定发送的信号,例如通过如下指令发送SIGINT信号:
docker-compose kill -s SIGINT
docker-compose config¶
查看docker-compose.yml的配置。
docker-compose config [options]
验证并查看compose文件配置。
选项包括:
–resolve-image-digests 将镜像标签标记为摘要
-q, –quiet 只验证配置,不输出。 当配置正确时,不输出任何内容,当文件配置错误,输出错误信息
–services 打印服务名,一行一个
–volumes 打印数据卷名,一行一个
docker-compose create¶
根据docker-compose.yml的配置文件信息,批量创建容器,但是不启动。
docker-compose create [options] [SERVICE...]
为服务创建容器。
选项包括:
–force-recreate:重新创建容器,即使配置和镜像没有改变,不兼容–no-recreate参数
–no-recreate:如果容器已经存在,不需要重新创建,不兼容–force-recreate参数
–no-build:不创建镜像,即使缺失
–build:创建容器前 ,生成镜像
docker-compose exec¶
进入docker-compose批量启动的某个容器中,相当于docker exec。
docker-compose exec [options] SERVICE COMMAND [ARGS...]
选项包括:
-d 分离模式,后台运行命令。
–privileged 获取特权。
–user USER 指定运行的用户。
-T 禁用分配TTY,默认docker-compose exec分配TTY。
–index=index,当一个服务拥有多个容器时,可通过该参数登陆到该服务下的任何服务,例如:docker-compose exec –index=1 web /bin/bash ,web服务中包含多个容器
docker-compose port¶
查看批量启动的某一个容器的开放端口
docker-compose port [options] SERVICE PRIVATE_PORT
显示某个容器端口所映射的公共端口。
选项包括:
–protocol=proto,指定端口协议,TCP(默认值)或者UDP
–index=index,如果同意服务存在多个容器,指定命令对象容器的序号(默认为1)
docker-compose push¶
批量推送容器服务器到docker镜像站(默认是dockerhub)。
3.5.3 模板配置项¶
docker-compose模板文件是一个定义服务、网络和卷的yaml文件。docker-compose模板文件默认路径是当前目录下的docker-compose.yml,可以使用.yml或.yaml作为文件扩展名。 docker-compose标准模板文件应该包含version、services、networks 三大部分,最关键的是services和networks两个部分。当然networks具有默认值,我们可以不填写。
例如,我们要一次性启动3个nginx容器运行各自不同的配置下。
docker-compose.yml,代码:
version: "3.9"
services:
web1:
image: nginx:1.25.3
container_name: "web1"
ports:
- "8081:80"
networks:
- dev
web2:
image: nginx:1.25.3
container_name: "web2"
ports:
- "8082:80"
networks:
- dev
web3:
image: nginx:1.25.3
container_name: "web3"
ports:
- "8083:80"
networks:
- dev
networks:
dev:
driver: bridge
docker-compose.yml,注释版本,代码:
# Compose 不同版本的compose提供的指令语法不一样。
# 目前我们使用的基本都是Version3版本,最新版本是3.9。
version: "3.9"
# 声明接下来开始配置服务容器
services:
# 服务名,开发者自定义的,
web1:
# image 当前服务容器的基本依赖镜像,如果本地没有该镜像,则会自动从官网pull拉取
# image 也可以是自己本地基于Dockerfile编译后产生的定制镜像,但是必须是已经build编译好的
# 如希望在docker-compose up启动容器服务时自动编译Dockerfile,则必须增加配置项build指定Dockerfile
# 文件的所在路径,如果不指定,则可能出现从官网拉取镜像失败的情况,build配置项写法如下:
# build: .
# 如使用了build配置项时还声明了image配置项,则基于build所在的Dockerfile编译的镜像名为image指定名字。
# build: .
# image: djdemo:1.0.0
image: nginx:1.25.3
# container_name 指定当前服务容器启动以后的容器名
container_name: "web1"
# ports 进行端口映射,值为数组,可以映射1个或多个端口
# - "外部端口:容器内部端口"
ports:
- "8081:80"
# networks 指定网络,可以分配容器在一个或多个网络,如果不指定,则默认分配在docker的default网络中
networks:
- dev
web2:
image: nginx:1.25.3
container_name: "web2"
ports:
- "8082:80"
networks:
- dev
- pro
web3:
image: nginx:1.25.3
container_name: "web3"
ports:
- "8083:80"
networks:
- pro
# 网络配置
networks:
# 指定网络名称,相当于网卡名networks:
dev:
driver: bridge
prod:
# driver 网卡驱动:bridge 桥接模式,网卡驱动有三种模式:bridge、host、none
# 查看网络:docker network ls
driver: bridge
根据上面的配置启动容器服务
# docker-compose up
# docker-compose -f docker-compose.yml up
docker-compose -f docker-compose.yml up -d
开放端口,让外界访问:
# 开放端口
firewall-cmd --list-ports
firewall-cmd --add-port=8081/tcp --permanent
firewall-cmd --add-port=8082/tcp --permanent
firewall-cmd --add-port=8083/tcp --permanent
firewall-cmd --reload
可以查看到不同容器之间得到网络
docker inspect web1 | grep IPAddress
docker inspect web2 | grep IPAddress
docker inspect web3 | grep IPAddress
可以使用以下命令删除与关闭容器服务
3.5.3.1 配置项说明¶
version-版本¶
设置当前docker-compose使用的配置语法版本。不同的语法版本对应不同的docker引擎提供的docker api。目前最新是3.9版本。
services-服务¶
设置当前工程下的容器服务有哪些,一般每个服务名都是按变量来定义,同时每一个服务都是一个容器,而且容器名与服务器同名。
image-基础镜像¶
image是指定服务的基础镜像的镜像名或镜像ID。如果镜像在本地不存在,Compose将会尝试拉取镜像。
注意:如果镜像有版本号,则镜像名和版本号之间不能出现空格!否则报错!!!
version: "3.9"
services:
web1: # 服务名
image: nginx:1.21.4 # 当前服务使用基础镜像
web2:
image: mysql:8.0.30 # 在本地不存在该镜像时,自动执行git pull mysql:8.0.30
build-构建自定义容器¶
docker-compose中的容器服务除了可以基于指定的官方镜像,还可以基于Dockerfile自定义镜像,在使用docker-compose up启动容器服务时,如果容器服务的配置选项中存在build,则可以指定Dockerfile所在文件夹的路径。docker-compose会将会利用Docker自动构建自定义镜像,然后再使用新的镜像启动容器服务。
version: "3.9"
services:
django:
build: /home/docker # 此处填写image镜像选项所需要的Dockerfile文件所在路径
image: mydjango:4.2.7 # docker-compose会判断本地镜像列表中是否存在mydjango:4.2.7,如果不存在,则根据build选项指定的路径使用Dockerfile编译镜像
如果同时指定image和build两个标签,那么Compose会构建镜像并且把镜像命名为image值指定的名字。
也可以是相对路径,只要上下文确定就可以读取到Dockerfile。
设定上下文根目录,然后以该目录为准指定Dockerfile。
version: "3.9"
services:
web:
image: mydjango:4.2.7
build:
context: ../docker
dockerfile: Dockerfile
context与build都是指定一个目录,如果要指定Dockerfile文件需要在build标签的子级标签中使用dockerfile标签指定。
version: "3.9"
services:
web:
image: mydjango:4.2.7
build:
context: /home/docker # 指定自定义镜像的配置文件的目录路径
dockerfile: Dockerfile # 指定自定义镜像的配置文件名,当配置文件名不是Dockerfile的时候,务必指定,否则docker-compose无法找到
context选项可以是Dockerfile的文件路径,也可以是到链接到git仓库的url,当提供的值是相对路径时,被解析为相对于撰写文件的路径,此目录也是发送到Docker守护进程的context
dockerfile选项可以指定context对应目录下的Dockerfile文件来构建,必须指定构建路径
ports¶
ports用于映射端口的标签。 使用HOST:CONTAINER格式或者只是指定容器的端口,宿主机会随机映射端口。
version: "3.9"
services:
web:
image: mydjango:4.2.7
build:
context: /home/docker # 指定自定义镜像的配置文件的目录路径
dockerfile: Dockerfile # 指定自定义镜像的配置文件名,当配置文件名不是Dockerfile的时候,务必指定,否则docker-compose无法找到
ports: # 设置当前容器的端口映射,相当于 docker -p
- "8000:8000"
# - "8081:8888"
当使用HOST:CONTAINER格式来映射端口时,如果使用的容器端口小于60可能会得到错误得结果,因为YAML将会解析xx:yy这种数字格式为60进制。所以建议采用字符串格式。
command¶
使用command可以覆盖容器启动后默认第一个执行的命令,相当于docker run 的最后一个参数
compose的command会覆盖Dockerfile里面的CMD的值。
version: "3.9"
services:
django:
build: /home/docker # 此处填写images镜像选项所需要的Dockerfile文件所在路径
image: mydjango:4.2.7 # docker-compose会判断本地镜像列表中是否存在django:4.0.7,如果不存在,则根据build选项指定的路径使用Dockerfile编译镜像
command: python manage.py runserver 0.0.0.0:8000
ports: # 设置当前容器的端口映射,相当于 docker -p
- "8001:8000"
container_name¶
docker-compose的容器名称格式是:<项目名称><服务名称><序号> 可以自定义项目名称、服务名称,但如果想完全控制容器的命名,可以使用标签指定:
version: "3.9"
services:
django:
build: /home/docker/
image: mydjango:4.2.7
container_name: django
command: python manage.py runserver 0.0.0.0:8888
ports:
- "8000:8888"
restart¶
指定是否在服务端开机以后,docker启动以后,是否容器也自动重启
version: "3.9"
services:
django:
build: /home/docker/
image:mydjango:4.2.7
container_name: django
restart: always # 设置容器服务开机自启
command: python manage.py runserver 0.0.0.0:8888
ports:
- "8000:8888"
environment¶
指定服务容器中的环境变量,可以多个环境变量,每个环境变量就一个成员
docker-compose-environment.yml,代码:
version: "3.9"
services:
mysql2:
image: mysql:latest
container_name: "mysql2"
restart: always
privileged: true
environment:
- "MYSQL_ROOT_PASSWORD=root" # 设置mysql用户的登陆密码
- "MYSQL_USER=sunday" # 设置新增用户
- "MYSQL_PASSWORD=123" # 新增用户的密码
- "MYSQL_DATABASE=sunday" # 设置新建数据库的名
- "TZ=Asia/Shanghai" # 设置数据库运行时的默认时区
ports:
- "3307:3306"
# 启动容器服务
docker-compose -f docker-compose-environment.yml up -d
# 关闭容器服务
docker-compose -f docker-compose-environment.yml down
depends_on¶
在使用docker-compose时,最大的好处就是使用最少的命令批量控制多个docker容器,但一般项目中多个容器的启动,启动容器的先后顺序是有要求的,如果直接从上到下启动容器,必然会因为容器依赖问题而部分容器启动失败。例如在没启动数据库容器的时候启动应用容器,应用容器会因为找不到数据库而退出。depends_on标签用于解决容器的依赖、启动先后顺序的问题
version: "3.9"
services:
sunday_api:
build: /home/docker/
image: mydjango:4.2.7
container_name: "sunday_api"
restart: always
ports:
- "8000:8000"
depends_on:
- mysql2
- redis2
mysql2:
image: mysql:latest
container_name: "mysql2"
restart: always
privileged: true
environment:
- "MYSQL_ROOT_PASSWORD=root" # 设置mysql用户的登陆密码
- "MYSQL_USER=sunday" # 设置新增用户
- "MYSQL_PASSWORD=123" # 新增用户的密码
- "MYSQL_DATABASE=sunday" # 设置新建数据库的名
- "TZ=Asia/Shanghai" # 设置数据库运行时的默认时区
ports:
- "3307:3306"
redis2:
image: redis
上述YAML文件定义的容器会先启动redis和db两个服务,最后才启动django服务。
volumes¶
挂载一个目录或者一个已存在的数据卷容器,可以直接使用 [HOST:CONTAINER]格式,或者使用[HOST:CONTAINER:ro]格式,后者对于容器来说,数据卷是只读的,可以有效保护宿主机的文件系统。 Compose的数据卷指定路径可以是相对路径,使用 . 或者 .. 来指定相对目录。
相当于 docker run 终端命令选项-v参数
数据卷的格式可以是下面多种形式
在容器外部,创建一个保存mysql数据的目录
目录结构:
docker-compose-vol.yml,代码:
version: "3.9"
services:
mysql:
image: mysql
restart: always
container_name: "mysql"
environment:
- "MYSQL_ROOT_PASSWORD=root" # 设置mysql用户的登陆密码
- "MYSQL_USER=sunday" # 设置新增用户
- "MYSQL_PASSWORD=sunday" # 新增用户的密码
- "MYSQL_DATABASE=sunday" # 设置新建数据库的名
- "TZ=Asia/Shanghai" # 设置数据库运行时的默认时区
ports:
- "3307:3306"
volumes:
- ./mysql/data:/var/lib/mysql # /var/lib/mysql 就是mysql容器保存数据库的路径
- ./mysql/conf:/etc/mysql/conf.d
启动服务
volumes选项的其他写法:
volumes:
# 只是指定一个路径,Docker 会自动在创建一个数据卷(这个路径是容器内部的)。
- /var/lib/mysql # 相当于 /var/lib/mysql:/var/lib/mysql
# 使用绝对路径挂载数据卷
- /home/compose/mysql/data:/var/lib/mysql
# 以 compose-compose.yml 配置文件为中心的相对路径作为数据卷挂载到容器。
- ./cache:/tmp/cache
# 使用用户的相对路径(~/ 表示的目录是 /home/<用户目录>/ 或者 /root/)。
- ~/configs:/etc/configs/:ro
# 已经存在的命名的数据卷。
- datavolume:/var/lib/mysql
如果不使用宿主机的路径,可以指定一个volume_driver。
volume_driver: sunday_driver
volumes_from¶
从另一个服务或容器挂载其数据卷:
dns¶
自定义DNS服务器。可以是一个值,也可以是一个列表。
expose¶
暴露端口,但不映射到宿主机,只允许能被连接的服务访问。仅可以指定内部端口为参数,如下所示:
links¶
链接到其它服务中的容器。使用服务名称(同时作为别名),或者“服务名称:服务别名”(如 SERVICE:ALIAS),例如:
net¶
设置网络模式。
3.5.4 搭建常用容器服务¶
3.5.4.1 搭建nginx负载均衡¶
终端执行命令:
先搭建了3台独立提供访问的nginx容器服务。docker-compose-nginx.yml,代码
version: "3.9"
services:
web1:
image: nginx:1.25.3
container_name: "web1"
restart: always
ports:
- "8081:80"
networks:
- dev
web2:
image: nginx:1.25.3
container_name: "web2"
restart: always
ports:
- "8082:80"
networks:
- dev
web3:
image: nginx:1.25.3
container_name: "web3"
restart: always
ports:
- "8083:80"
networks:
- dev
networks:
dev:
driver: bridge
使用web1作为反向代理服务器,提供让用户访问web1时,web1进行反向代理,把请求转发给web2和web3.
需要单独提供一个nginx配置文件给web1代理服务器,终端执行:
mkdir -p /home/compose/nginx/conf
vi /home/compose/nginx/conf/nginx.conf
upstream web {
server 192.168.233.152:8082 weight=2; # 注意,此处的IP绝对不能是127.0.0.1!!!
server 192.168.233.152:8083 weight=1;
}
server {
listen 80;
server_name localhost;
location / {
proxy_pass http://web; # 反向代理,web指向上面的服务器组
}
}
# :wq
调整docker-compose-nginx.yml中web1容器服务,使用上面新增的nginx配置,代码:
version: "3.9"
services:
web1:
image: nginx:1.25.3
container_name: "web1"
restart: always
ports:
- "8081:80"
networks:
- dev
volumes:
- ./conf:/etc/nginx/conf.d
web2:
image: nginx:1.25.3
container_name: "web2"
restart: always
ports:
- "8082:80"
networks:
- dev
web3:
image: nginx:1.25.3
container_name: "web3"
restart: always
ports:
- "8083:80"
networks:
- dev
networks:
dev:
driver: bridge
保存文件以后,把原来的容器服务重启,终端操作:
# 关闭 docker-compose-nginx.yml 配置的容器服务
docker-compose -f docker-compose-nginx.yml down
# 启动 docker-compose-nginx.yml 配置的容器服务
docker-compose -f docker-compose-nginx.yml up -d
# 开放端口【如果已经开启则跳过即可】
firewall-cmd --list-ports
firewall-cmd --add-port=8081/tcp --permanent
firewall-cmd --add-port=8082/tcp --permanent
firewall-cmd --add-port=8083/tcp --permanent
firewall-cmd --reload
# 查看日志,在下一步访问站点时,观察是否成功进行反向代理和负载均衡调度了。
docker-compose -f docker-compose-nginx.yml logs -f
通过浏览器访问web1
3.5.4.2 搭建mysql的单点服务¶
docker-compose-single-mysql.yml,代码:
version: '3.9'
services:
mysql:
image: mysql:8.0.30
restart: always
privileged: true
container_name: mysql
networks:
- mysql
environment:
- "MYSQL_ROOT_PASSWORD=root"
- "MYSQL_USER=fuguang"
- "MYSQL_PASSWORD=fuguang"
- "MYSQL_DATABASE=fuguang"
- "TZ=Asia/Shanghai"
command:
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
ports:
- 3306:3306
volumes:
- ./mysql/conf:/etc/mysql/conf.d/ # 配置文件存储目录
- ./mysql/data:/var/lib/mysql # 数据存储目录
- ./mysql/logs:/var/lib/logs # 日志目录
- ./mysql/initdb:/docker-entrypoint-initdb.d/ # SQL语句初始化目录
networks:
mysql:
docker-compose -f docker-compose-single-mysql.yml up -d
# 如果出现端口被占用,则修改yml中的mysql端口3307
# ports:
# - 3307:3306
docker exec -it mysql mysql -uroot -proot
# exit
# 也可以使用fuguang_user登录数据库
docker exec -it mysql mysql -ufuguang_user -pfuguang
show databases;
上面的运行是没有设置数据库配置的,所以还可以在当前目录下mysql/conf/my.cnf,代码:
[mysqld]
bind-address=0.0.0.0
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
log-error=/tmp/logs/mysql.err
init_connect='SET NAMES utf8mb4'
skip-character-set-client-handshake=true
server-id=1
log-bin=mysql-logbin
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
关闭现有的服务容器,再次基于配置文件,生成服务容器。
docker-compose -f docker-compose-singel-mysql.yml down
docker-compose -f docker-compose-single-mysql.yml up -d
docker exec -it mysql mysql -ufuguang_user -pfuguang
3.5.4.3 搭建mysql的主从服务¶
3.5.4.4 搭建redis的单点服务¶
port 6379
bind 0.0.0.0
pidfile /usr/local/src/redis/data/redis.pid
loglevel notice
dir /data
protected-mode yes
dbfilename dump.rdb
rdbcompression yes
save 900 1
save 300 10
save 60 10000
appendonly yes
appendfilename appendonly.aof
appendfsync everysec
user default on nopass sanitize-payload ~* &* +@all
user fuguang on #a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3 ~* resetchannels +@all
docker-compose-single-redis.yml,代码:
version: '3.9'
services:
redis:
image: redis:6.2.6-alpine3.15
container_name: redis-master
restart: always
privileged: true
command: redis-server /usr/local/etc/redis/redis.conf
volumes:
- "./redis/conf/redis.conf:/usr/local/etc/redis/redis.conf"
- "./redis/data:/data"
ports:
- "6379:6379"
补充:
redis提供的rdb数据备份功能实际上由2种触发机制:
1. 在redis.conf配置文件中,通过save配置自动触发的
2. 在redis-cli等客户端下,可以通过bgsave来手动触发。当客户端执行bgsave时,有redis-server服务端单独创建一个子进程进行异步非阻塞备份。
3.5.4.5 搭建redis的主从服务¶
主从复制原理:
- 从服务器连接主服务器,发送SYNC命令;
- 主服务器接收到SYNC命令后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令;
- 主服务器执行完BGSAVE后,向所有从服务器发送RDB快照文件,并在发送期间继续记录被执行的写命令;
- 从服务器收到RDB快照文件后丢弃所有旧数据,载入收到的快照;
- 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
- 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;(从服务器初始化完成)
- 主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令(从服务器初始化完成后的操作)
主从复制优缺点
优点:
- 支持读写分离,主数据库会自动将数据同步到从数据库,可以进行读写分离。
- 从数据库分担主数据库的读操作压力,从数据库可以为客户端提供读操作,写操作仍然由主数据库来完成。
- 从数据库同样可以接受其它从数据库的连接和同步请求,这样可以有效的分担主数据库的同步压力。
- 从数据库以非阻塞方式为其他的从数据库提供服务。所以在主从同步期间客户端仍然可以对redis提交查询或修改请求。
- 从数据库同样是以非阻塞的方式完成数据同步。在同步主数据库数据期间,如果有客户端提交查询请求,Redis则返回同步之前的数据。
缺点:
- Redis不具备自动容错和恢复功能,主数据库或从数据库的宕机都会导致客户端读写请求失败,需要等待机器重启或者手动切换数据库的连接IP才能恢复。
- 主数据库宕机,宕机前有部分数据未能及时同步到从数据库,切换IP后还会引入数据不一致的问题,降低了系统的可用性。
- 单机的Redis较难支持在线扩容,在容量达到上限时在线扩容会变得很复杂。解决的方案是可以使用分布式集群。
docker-compose-reids-ms.yml,代码:
version: "3.9"
services:
master:
image: redis:6.2.6-alpine3.15
container_name: redis-master
restart: always
command: redis-server --requirepass 123456
ports:
- "6379:6379"
privileged: true
slave1:
image: redis:6.2.6-alpine3.15
container_name: redis-slave-1
restart: always
ports:
- "6380:6379"
command: redis-server --replicaof redis-master 6379 --requirepass 123456 --masterauth 123456
depends_on:
- master
slave2:
image: redis:6.2.6-alpine3.15
container_name: redis-slave-2
restart: always
ports:
- "6381:6379"
command: redis-server --replicaof redis-master 6379 --requirepass 123456 --masterauth 123456
depends_on:
- master
docker-compose -f docker-compose-reids-ms.yml up -d
docker exec -it redis-master redis-cli
# auth 123456
# info replication
# set name xiaoming
# exit
docker exec -it redis-slave-1 redis-cli
# auth 123456
# info replication
# get name # --> xiaoming
# set name # 报错,因为从数据库无法写入数据,只能读取数据
注意:主从架构虽然可以让项目架构支撑更高的访问量,但是主从架构默认情况下是没有容灾机制的。所以我们为了提高整个项目架构的高可用性,也就是提高容灾性,会选择采用哨兵集群模式。
3.5.4.6 搭建redis的哨兵集群¶
搭建哨兵服务¶
哨兵(sentinel)是特殊的redis服务,不提供读写数据服务,主要用来监控redis实例节点。
哨兵模式(Redis-Sentinel)是官方推荐的高可用解决方案,上面redis在做master-slave主从复制的高可用方案时,假如master宕机了,redis本身(以及其很多客户端)都没有实现自动进行主从切换,而redis-sentinel本身也是独立运行的进程,可以部署在其他与redis集群可通讯的机器中监控redis集群。
哨兵的作用就是监控Redis系统的运行状况。其功能包括以下:
(1)监控主数据库和从数据库是否正常运行。 往往一个哨兵监控一个redis。 (2)主数据库出现故障时哨兵集群基于决策自动将其中一台从数据库转换为主数据库,当后面旧主数据库上线以后,会被切换成新的从数据库。
哨兵的工作方式:
- 每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的redis主数据库,从数据库以及其他Sentinel(哨兵)进程发送一个 PING 命令。
- 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线(SDOWN)
- 如果一个redis主数据库被标记为主观下线(SDOWN),则正在监视这个主数据库的所有 Sentinel(哨兵)进程要以每秒一次的频率确认主数据库真的进入了主观下线状态
- 当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认主数据库进入了主观下线状态(SDOWN), 则主数据库会被标记为客观下线(ODOWN)
- 在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有主数据库、从数据库发送 INFO 命令。(INFO 命令用于表明自己在整个集群中的身份:master/slave/sentinel)
- 当主数据库被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的主数据库的所有 从数据库发送 INFO 命令的频率会从 10 秒一次改为每秒一次。(开启选举决策,所有从数据库会进入竞选状态,从中产生1台新的主数据库)
- 若没有足够数量的 Sentinel(哨兵)进程同意主数据库下线, 主数据库的客观下线状态就会被移除。若主数据库重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,主数据库的主观下线状态就会被移除。(没有出现新的主数据库之前,如果客观下线过程中产生了新的主数据库,则原来的主数据库在重新上线以后,会变成新的主数据库的从库运行。)
哨兵模式的优缺点
优点:
- 哨兵模式是基于主从模式扩展出来的,所以哨兵模式具有主从模式的所有优点。
- 哨兵模式下主从可以在主数据库客观下线以后基于竞选决策会自动切换,让系统更健壮,具有更高的可用性、容灾性。
缺点:
- Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。(解决方案:Codis或Redis-Cluster等分布式集群方案)
工作中最常用的哨兵集群方案:一主二从三哨兵
docker-compose-redis-sentinel.yml,代码:
version: '3.9'
services:
redis-master:
image: redis:6.2.6-alpine3.15
container_name: redis-master
restart: always
command: redis-server /usr/local/etc/redis/master.conf
volumes:
- "./sentinel/redis/master.conf:/usr/local/etc/redis/master.conf"
ports:
- "6379:6379"
privileged: true
networks:
sentinel:
ipv4_address: 192.168.5.11
redis-slave1:
image: redis:6.2.6-alpine3.15
container_name: redis-slave-1
restart: always
ports:
- "6380:6379"
command: redis-server /usr/local/etc/redis/slave.conf
volumes:
- "./sentinel/redis/slave.conf:/usr/local/etc/redis/slave.conf"
depends_on:
- redis-master
networks:
sentinel:
ipv4_address: 192.168.5.12
redis-slave2:
image: redis:6.2.6-alpine3.15
container_name: redis-slave-2
restart: always
ports:
- "6381:6379"
command: redis-server /usr/local/etc/redis/slave.conf
volumes:
- "./sentinel/redis/slave.conf:/usr/local/etc/redis/slave.conf"
depends_on:
- redis-master
networks:
sentinel:
ipv4_address: 192.168.5.13
redis-sentinel1:
image: redis:6.2.6-alpine3.15
container_name: redis-sentinel-1
restart: always
ports:
- "26379:26379"
command: redis-sentinel /usr/local/etc/redis/sentinel.conf
volumes:
- "./sentinel/redis/sentinel.conf:/usr/local/etc/redis/sentinel.conf"
depends_on:
- redis-master
- redis-slave1
- redis-slave2
networks:
sentinel:
ipv4_address: 192.168.5.14
redis-sentinel2:
image: redis:6.2.6-alpine3.15
container_name: redis-sentinel-2
restart: always
ports:
- "26380:26379"
command: redis-sentinel /usr/local/etc/redis/sentinel.conf
volumes:
- "./sentinel/redis/sentinel.conf:/usr/local/etc/redis/sentinel.conf"
depends_on:
- redis-master
- redis-slave1
- redis-slave2
networks:
sentinel:
ipv4_address: 192.168.5.15
redis-sentinel3:
image: redis:6.2.6-alpine3.15
container_name: redis-sentinel-3
restart: always
ports:
- "26381:26379"
command: redis-sentinel /usr/local/etc/redis/sentinel.conf
volumes:
- "./sentinel/redis/sentinel.conf:/usr/local/etc/redis/sentinel.conf"
depends_on:
- redis-master
- redis-slave1
- redis-slave2
networks:
sentinel:
ipv4_address: 192.168.5.16
networks:
sentinel:
driver: bridge
ipam:
driver: default
config:
- subnet: 192.168.5.0/24
cd /home/compose
mkdir -p sentinel/redis
vim sentinel/redis/master.conf
vim sentinel/redis/slave.conf
vim sentinel/redis/sentinel.conf
sentinel/redis/master.conf,主库配置文件,代码:
sentinel/redis/slave.conf,从库配置文件,代码:
replicaof redis-master 6379
requirepass 123456
masterauth 123456
bind 0.0.0.0
# Generated by CONFIG REWRITE
dir "/data"
sentinel/redis/sentinel.conf,哨兵配置文件,代码:
port 26379
dir "/data"
sentinel deny-scripts-reconfig yes
sentinel monitor mymaster 192.168.5.11 6379 2
sentinel down-after-milliseconds mymaster 3000
sentinel failover-timeout mymaster 3000
sentinel auth-pass mymaster 123456
sentinel config-epoch mymaster 0
# Generated by CONFIG REWRITE
sentinel leader-epoch mymaster 0
sentinel known-replica mymaster 192.168.5.12 6379
sentinel known-replica mymaster 192.168.5.13 6379
sentinel current-epoch 0
配置完成,接下来启动服务。
docker-compose -f docker-compose-redis-sentinel.yml up -d
docker exec -it redis-master redis-cli
# auth 123456
# info replication
# set name xiaoming
# exit
docker exec -it redis-slave-1 redis-cli
# auth 123456
# info replication
# get name # --> xiaoming
# set name xiaohong # 报错,因为从数据库无法写入数据,只能读取数据
# exit
# 查看哨兵服务的监控
docker exec -it redis-sentinel-1 redis-cli -p 26379
# info sentinel
# 关闭主库
docker stop redis-master
# 等待30秒以后,观察哨兵是否选举出了新的主库。
docker exec -it redis-slave-1 redis-cli
# auth 123456
# info replication
docker exec -it redis-slave-2 redis-cli
# auth 123456
# info replication
# 启动redis-master容器,查看是否自动切换成了从库。
docker start redis-master
docker exec -it redis-master redis-cli
# auth 123456
# info replication
搭建分布式集群¶
特点
在Redis 3.0版本以后,Redis发布了Redis Cluster。Redis Cluster是社区版推出的Redis分布式集群解决方案,Redis Cluster主要解决Redis分布式方面的需求,着眼于提高并发量以支持高并发和海量数据处理等业务。比如当遇到单机内存,并发和流量等瓶颈的时候,Redis Cluster能起到很好的负载均衡的目的。Redis集群既实现了主从复制,也兼顾了哨兵的选举模式。
优势
① 自动分割数据到不同的节点上。基于哈希槽保存数据
② 整个集群的部分节点失败或者不可达的情况下能够继续处理命令。
key=name ----> CRC16(name) ----> 5798
key=age ----> CRC16(age) → 741
5798%16384 = 0...5798
741%16384 = 0... 741
[]...[]....741[age]...[][][]...5798[name][][]
哈希槽
Redis Cluster集群固定由16384个哈希槽,每个数据的key通过CRC16校验算后对16384取模来决定key对应的数据放置哪个槽,集群的每个服务器节点负责一部分hash槽,也就是说数据存放在hash槽里,而每个服务器节点只负责部分hash槽(这样数据就存放在不同的服务器节点)。
redis-cluster的源码文件src/cluster.c中声明了keyHashSlot函数中基于CRC16校验算法计算指定key应该被分配到哪个槽。
相关文档:https://github.com/y123456yz/Reading-and-comprehense-redis-cluster
集群搭建
redis-cluster群集至少需要3主3从,且每个实例使用不同的配置文件。
此处的IP,需要查看当前宿主机的IP网卡地址。
mkdir -p cluster/conf
touch cluster/conf/redis-637{1..6}.conf
echo -e '# 端口\nport 6371\n# 是否开启集群模式,默认 no\ncluster-enabled yes\n# 集群节点信息文件\ncluster-config-file nodes-6371.conf\n# 集群节点连接超时时间\ncluster-node-timeout 15000\n# aof模式开启和aof数据文件名\nappendonly yes\nappendfilename "appendonly-6371.aof"\n# rdb数据文件名\ndbfilename dump-6371.rdb\n# 设置密码\nrequirepass 123456\n# 从节点访问主节点密码(必须与 requirepass 一致)\nmasterauth 123456\n# 集群节点 IP(宿主机IP)\ncluster-announce-ip 192.168.233.150\n# 集群节点映射端口\ncluster-announce-port 6371\n# 集群节点总线端口\ncluster-announce-bus-port 16371' > cluster/conf/redis-6371.conf
echo -e '# 端口\nport 6372\n# 是否开启集群模式,默认 no\ncluster-enabled yes\n# 集群节点信息文件\ncluster-config-file nodes-6372.conf\n# 集群节点连接超时时间\ncluster-node-timeout 15000\n# aof模式开启和aof数据文件名\nappendonly yes\nappendfilename "appendonly-6372.aof"\n# rdb数据文件名\ndbfilename dump-6372.rdb\n# 设置密码\nrequirepass 123456\n# 从节点访问主节点密码(必须与 requirepass 一致)\nmasterauth 123456\n# 集群节点 IP(宿主机IP)\ncluster-announce-ip 192.168.233.150\n# 集群节点映射端口\ncluster-announce-port 6372\n# 集群节点总线端口\ncluster-announce-bus-port 16372' > cluster/conf/redis-6372.conf
echo -e '# 端口\nport 6373\n# 是否开启集群模式,默认 no\ncluster-enabled yes\n# 集群节点信息文件\ncluster-config-file nodes-6373.conf\n# 集群节点连接超时时间\ncluster-node-timeout 15000\n# aof模式开启和aof数据文件名\nappendonly yes\nappendfilename "appendonly-6373.aof"\n# rdb数据文件名\ndbfilename dump-6373.rdb\n# 设置密码\nrequirepass 123456\n# 从节点访问主节点密码(必须与 requirepass 一致)\nmasterauth 123456\n# 集群节点 IP(宿主机IP)\ncluster-announce-ip 192.168.233.150\n# 集群节点映射端口\ncluster-announce-port 6373\n# 集群节点总线端口\ncluster-announce-bus-port 16373' > cluster/conf/redis-6373.conf
echo -e '# 端口\nport 6374\n# 是否开启集群模式,默认 no\ncluster-enabled yes\n# 集群节点信息文件\ncluster-config-file nodes-6374.conf\n# 集群节点连接超时时间\ncluster-node-timeout 15000\n# aof模式开启和aof数据文件名\nappendonly yes\nappendfilename "appendonly-6374.aof"\n# rdb数据文件名\ndbfilename dump-6374.rdb\n# 设置密码\nrequirepass 123456\n# 从节点访问主节点密码(必须与 requirepass 一致)\nmasterauth 123456\n# 集群节点 IP(宿主机IP)\ncluster-announce-ip 192.168.233.150\n# 集群节点映射端口\ncluster-announce-port 6374\n# 集群节点总线端口\ncluster-announce-bus-port 16374' > cluster/conf/redis-6374.conf
echo -e '# 端口\nport 6375\n# 是否开启集群模式,默认 no\ncluster-enabled yes\n# 集群节点信息文件\ncluster-config-file nodes-6375.conf\n# 集群节点连接超时时间\ncluster-node-timeout 15000\n# aof模式开启和aof数据文件名\nappendonly yes\nappendfilename "appendonly-6375.aof"\n# rdb数据文件名\ndbfilename dump-6375.rdb\n# 设置密码\nrequirepass 123456\n# 从节点访问主节点密码(必须与 requirepass 一致)\nmasterauth 123456\n# 集群节点 IP(宿主机IP)\ncluster-announce-ip 192.168.233.150\n# 集群节点映射端口\ncluster-announce-port 6375\n# 集群节点总线端口\ncluster-announce-bus-port 16375' > cluster/conf/redis-6375.conf
echo -e '# 端口\nport 6376\n# 是否开启集群模式,默认 no\ncluster-enabled yes\n# 集群节点信息文件\ncluster-config-file nodes-6376.conf\n# 集群节点连接超时时间\ncluster-node-timeout 15000\n# aof模式开启和aof数据文件名\nappendonly yes\nappendfilename "appendonly-6376.aof"\n# rdb数据文件名\ndbfilename dump-6376.rdb\n# 设置密码\nrequirepass 123456\n# 从节点访问主节点密码(必须与 requirepass 一致)\nmasterauth 123456\n# 集群节点 IP(宿主机IP)\ncluster-announce-ip 192.168.233.150\n# 集群节点映射端口\ncluster-announce-port 6376\n# 集群节点总线端口\ncluster-announce-bus-port 16376' > cluster/conf/redis-6376.conf
docker-compose-redis-cluster.yml,代码:
version: "3.9"
services:
redis-6371:
image: redis:6.2.6-alpine3.15
container_name: redis-6371
restart: always
privileged: true
ports:
- 6371:6371
- 16371:16371
command: "redis-server /usr/local/etc/redis/redis.conf"
volumes:
- ./cluster/conf/redis-6371.conf:/usr/local/etc/redis/redis.conf
- ./cluster/data/redis-6371:/data
redis-6372:
image: redis:6.2.6-alpine3.15
container_name: redis-6372
restart: always
privileged: true
ports:
- 6372:6372
- 16372:16372
command: "redis-server /usr/local/etc/redis/redis.conf"
volumes:
- ./cluster/conf/redis-6372.conf:/usr/local/etc/redis/redis.conf
- ./cluster/data/redis-6372:/data
redis-6373:
image: redis:6.2.6-alpine3.15
container_name: redis-6373
restart: always
privileged: true
ports:
- 6373:6373
- 16373:16373
command: "redis-server /usr/local/etc/redis/redis.conf"
volumes:
- ./cluster/conf/redis-6373.conf:/usr/local/etc/redis/redis.conf
- ./cluster/data/redis-6373:/data
redis-6374:
image: redis:6.2.6-alpine3.15
container_name: redis-6374
restart: always
privileged: true
ports:
- 6374:6374
- 16374:16374
command: "redis-server /usr/local/etc/redis/redis.conf"
volumes:
- ./cluster/conf/redis-6374.conf:/usr/local/etc/redis/redis.conf
- ./cluster/data/redis-6374:/data
redis-6375:
image: redis:6.2.6-alpine3.15
container_name: redis-6375
restart: always
privileged: true
ports:
- 6375:6375
- 16375:16375
command: "redis-server /usr/local/etc/redis/redis.conf"
volumes:
- ./cluster/conf/redis-6375.conf:/usr/local/etc/redis/redis.conf
- ./cluster/data/redis-6375:/data
redis-6376:
image: redis:6.2.6-alpine3.15
container_name: redis-6376
restart: always
privileged: true
ports:
- 6376:6376
- 16376:16376
command: "redis-server /usr/local/etc/redis/redis.conf"
volumes:
- ./cluster/conf/redis-6376.conf:/usr/local/etc/redis/redis.conf
- ./cluster/data/redis-6376:/data
构建集群
docker-compose -f docker-compose-redis-cluster.yml up -d
# 进入其中一台redis容器
docker exec -it redis-6371 sh
# 构建集群
redis-cli -a 123456 --cluster create \
192.168.233.150:6371 192.168.233.150:6372 \
192.168.233.150:6373 192.168.233.150:6374 \
192.168.233.150:6375 192.168.233.150:6376 \
--cluster-replicas 1
# yes
# 完成!!!!
验证效果
### 连接集群
redis-cli -c -a 123456 -h 192.168.233.150 -p 6376
set name xiaoming
# -> Redirected to slot [5798] located at 192.168.233.150:6372
# OK
get name
# -> Redirected to slot [5798] located at 192.168.233.150:6372
# "xiaoming"
set age 18
# -> Redirected to slot [741] located at 192.168.233.150:6371
# OK
get age
# -> Redirected to slot [741] located at 192.168.233.150:6371
# "18"
### 检查集群状态
redis-cli -a 123456 --cluster check 192.168.233.150:6371
# Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
# 192.168.233.150:6371 (59d7ca6b...) -> 1 keys | 5461 slots | 1 slaves.
# 192.168.233.150:6373 (1f84e3ef...) -> 0 keys | 5461 slots | 1 slaves.
# 192.168.233.150:6372 (eb58af9e...) -> 1 keys | 5462 slots | 1 slaves.
# [OK] 2 keys in 3 masters.
# 0.00 keys per slot on average.
# >>> Performing Cluster Check (using node 192.168.233.150:6371)
# M: 59d7ca6bbdcd297a79132b646b98e0dc32bf6cb8 192.168.233.150:6371
# slots:[0-5460] (5461 slots) master
# 1 additional replica(s)
# M: 1f84e3efc066ba0e975162f36a7c2d572ea1d610 192.168.233.150:6373
# slots:[10923-16383] (5461 slots) master
# 1 additional replica(s)
# S: 43234e3bcdb7c18e170819d0cb07795e919187f8 192.168.233.150:6376
# slots: (0 slots) slave
# replicates eb58af9e0d2d710db98ef59babddeca6199a53c2
# S: 0b28b840fa466a0c97bebe40b4e209fc289bc8ae 192.168.233.150:6374
# slots: (0 slots) slave
# replicates 1f84e3efc066ba0e975162f36a7c2d572ea1d610
# M: eb58af9e0d2d710db98ef59babddeca6199a53c2 192.168.233.150:6372
# slots:[5461-10922] (5462 slots) master
# 1 additional replica(s)
# S: 6dd3a27a5b9ba6c7f7af09747040c425e3fbe9bf 192.168.233.150:6375
# slots: (0 slots) slave
# replicates 59d7ca6bbdcd297a79132b646b98e0dc32bf6cb8
# [OK] All nodes agree about slots configuration.
# >>> Check for open slots...
# >>> Check slots coverage...
# [OK] All 16384 slots covered.
# 测试选举
# 关闭一个主库,例如:redis-6371
docker stop redis-6371
# 进入其中一台redis容器
docker exec -it redis-6376 sh
# 进入上面主库对应的从库,例如:6371的从库是6375
redis-cli -c -a 123456 -h 192.168.233.150 -p 6375
info replication
# 可以看到从库被选举成了主库,而且没有从库
# 退出容器,再次启动原来的主库,例如:6371
# exit
docker start redis-6371
# 进入其中一台redis容器
docker exec -it redis-6371 sh
# 进入刚刚主库,例如:6371
redis-cli -c -a 123456 -h 192.168.233.150 -p 6371
info replication
# 可以看到刚启动6371由原来的主库变成了从库
注意:Redis Cluster集群不能保证数据的强一致性。主要原因是Redis集群采用异步写的方法,即当客户端向Master主库写入一条数据后,Master主库先进行主从数据异步写入到从库,然后再给客户端返回一个执行结果,这样当客户端完成写入并拿到Master返回的结果时(Master有可能还未来得及执行主从同步),此时如果该Master主库出现宕机或网络不可达,就出现了数据不一致的情况,这就是Redis的异步写的缺点。但是如果Redis集群采用同步写,那么整个集群的性能将大大下降(即:客户端写入数据后,Master先执行主从同步,然后才返回写入结果给客户端)。
3.5.4.7 搭建mongoDB的单点服务¶
3.5.4.8 搭建mongoDB的复制集服务(主从)¶
3.5.4.9 搭建mongoDB的分片集服务(集群)¶
3.5.4.10 搭建elasticsearch单点服务¶
docker-compose-single-elasticsearch.yml,代码:
version: "3.9"
services:
elasticsearch:
image: elasticsearch:7.16.1
environment:
- "discovery.type=single-node"
- "bootstrap.memory_lock=true"
- "ES_JAVA_OPTS=-Xms256m -Xmx256m"
- "xpack.security.enabled=false"
- "http.cors.enabled=true"
- "http.cors.allow-origin=*"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- ./data/elastic:/usr/share/elasticsearch/data
- ./log/elastic:/var/log/elasticsearch
- ./plugins:/usr/share/elasticsearch/plugins
ports:
- 9200:9200
networks:
- default
networks:
default:
接下来,我们可以把elasticsearch容器和ik中文分词器一步到位的集成进来。
ik分词器下载:https://github.com/medcl/elasticsearch-analysis-ik/releases
注意:ik分词器仅支持中文分词,如果要基于亚洲其他国家(如日文、韩文等)则可以采用官方提供的icu分词器插件来集成实现,icu的使用和ik分词器一样。
mkdir -p /home/compose/data/elastic
chmod 777 /home/compose/data/elastic
mkdir -p /home/compose/plugins
wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.16.1/elasticsearch-analysis-ik-7.16.1.zip
unzip elasticsearch-analysis-ik-7.16.1.zip -d /home/compose/plugins/ik-7.16.1
# 防火墙开放端口:9200
firewall-cmd --add-port=9200/tcp --permanent
firewall-cmd --reload
docker-compose -f docker-compose-single-elasticsearch.yml up -d
测试:
post http://192.168.233.150:9200/_analyze?pretty
{
"analyzer":"standard", // es内置标准分词
// "analyzer":"ik_max_word", // ik最大分词
// "analyzer":"ik_smart", // ik智能分词
"text": "我是中国人,我来自北京。"
}
3.5.4.11 搭建elasticsearch集群服务¶
文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.16/docker.html
docker-compose-elasticsearch-cluster.yml,代码:
version: '3.9'
services:
es01:
image: docker.elastic.co/elasticsearch/elasticsearch:7.16.1
container_name: es01
environment:
- node.name=es01
- cluster.name=es-docker-cluster
- discovery.seed_hosts=es02,es03
- cluster.initial_master_nodes=es01,es02,es03
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- data01:/usr/share/elasticsearch/data
- ./plugins:/usr/share/elasticsearch/plugins
ports:
- 9200:9200
networks:
- elastic
es02:
image: docker.elastic.co/elasticsearch/elasticsearch:7.16.1
container_name: es02
environment:
- node.name=es02
- cluster.name=es-docker-cluster
- discovery.seed_hosts=es01,es03
- cluster.initial_master_nodes=es01,es02,es03
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- data02:/usr/share/elasticsearch/data
- ./plugins:/usr/share/elasticsearch/plugins
networks:
- elastic
es03:
image: docker.elastic.co/elasticsearch/elasticsearch:7.16.1
container_name: es03
environment:
- node.name=es03
- cluster.name=es-docker-cluster
- discovery.seed_hosts=es01,es02
- cluster.initial_master_nodes=es01,es02,es03
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- data03:/usr/share/elasticsearch/data
- ./plugins:/usr/share/elasticsearch/plugins
networks:
- elastic
volumes:
data01:
driver: local
data02:
driver: local
data03:
driver: local
networks:
elastic:
driver: bridge
启动服务容器
# 解决es启动时内存过小导致宕机的情况
vim /etc/sysctl.conf
文件最后添加一行: vm.max_map_count=262144
sysctl -p
docker-compose -f docker-compose-elasticsearch-cluster.yml up -d
测试:
post http://192.168.233.150:9200/_analyze?pretty
{
"analyzer":"standard", // es内置标准分词
// "analyzer":"ik_max_word", // ik最大分词
// "analyzer":"ik_smart", // ik智能分词
"text": "我是中国人,我来自北京。"
}
注意
在实际工作中,es的常用集群部署有2种类型:
- docker部署
- 源码包安装,而源码包有2种格式:
- zip包
- tar包
需要注意的是:tar包安装的es不能与zip包安装的es组成集群!也就是说只能是tar+tar组建集群或者zip+zip组建集群!!!



















































