我在不同的数据库上运行了这个 ssh 命令:
ssh -i $8 -l $9 $1 "set -o pipefail set -o StrictHostKeyChecking=no; mysqldump --single-transaction --skip-lock-tables -u $2 -p$3 -P $4 -h $5 $6" | gzip -c > $7;
这些变量是该命令的参数。
它可以工作,除非 IP 地址的后端发生变化,尽管有set -o StrictHostkeyChecking=no
,我收到以下消息:
Offending ECDSA key in /home/admin/.ssh/known_hosts:130
remove with:
ssh-keygen -f "/home/admin/.ssh/known_hosts" -R "172.30.0.63"
ECDSA host key for 172.30.0.63 has changed and you have requested strict checking.
Host key verification failed.
命令有问题,但我不确定哪里有问题。我尝试了几种不同的变体,但没有成功。
答案1
该StrictHostKeyChecking=no
参数需要作为 ssh 命令的选项传递,而不是作为远程 shell 命令的选项。例如:
ssh -i "$8" -o StrictHostKeyChecking=no -l "$9" "$1" "
set -o pipefail; mysqldump --single-transaction --skip-lock-tables -u $2 -p$3 -P $4 -h $5 $6
" | gzip -c > "$7"
(我在这里对参数扩展进行了双引号,因为尽管您没有提及您正在使用哪个本地 shell,但许多 shell 都会对分词和文件名生成进行未加引号的扩展。)
请注意,此选项不会抑制有关可能的 MiM 攻击的警告。
答案2
如果在运行时使用命令行选项禁用不起作用,请在文件中禁用它~/.ssh/config
。如果该文件不存在,您可以创建该文件,请记住使用或with 为其授予rw-r-r
权限 ,然后添加以下内容:chmod 644 ~/.ssh/config
rw-
chmod 600 ~/.ssh/config
Host *
StrictHostKeyChecking no
也检查这个帖子: 如何在 ssh 中禁用严格的主机密钥检查?
答案3
我通常不会告诉其他人如何运行他们的服务器管理,但是......
如果您发现自己将八个变量传递给单行 shell 脚本,那么您所做的事情非常糟糕,可怕地错误的。
让我们从简化开始。
首先,SSH 位:
我将给你一个毫无疑问的好处,并假设每个变量是实际上是可变的,你有多个主机,每个其中需要以具有不同身份文件的不同用户身份进行访问,没有任何其中可以指望拥有正确的主机密钥,并且您无权更改上述任何内容。
(我不会给你写五页充满谩骂的关于一致性和适当安全措施的咆哮;请阅读)
将以下内容添加到~/.ssh/config
您打算用于此目的的任何管理员帐户:
Host foo
StrictHostKeyChecking No
HostName 172.30.0.63
User foouser
IdentityFile ~/.ssh/id_foo.ed25519
Host bar
StrictHostKeyChecking No
HostName bar.internal.elsewhere
User baruser
IdentityFile ~/.ssh/id_bar.ecdsa
Host qux
StrictHostKeyChecking No
HostName qux.eternal.universe
User quxuser
IdentityFile ~/.ssh/id_qux.rsa
等等。此时,您可以在命令行上省略$8
和,$9
正如-o StrictHostKeyChecking No
Steeldriver 指出的那样,它一开始就完全位于错误的位置。
其次,mysqldump部分。
这就是自动化软件的用途安西布尔闪闪发光。
首先,您创建一个 ansible inventory,如下所示:
all:
dbservers:
hosts:
foo:
bar:
qux:
此处使用与文件中相同的命名约定~/.ssh/config
。用于ansible -m ping dbservers
检查您是否正确,并根据需要纠正错误。
然后在 中添加以下内容host_vars/baz/vars.yaml
:
mysql_db_user: 'bazdbuser'
mysql_db_password: 'bazdbpassword'
mysql_db_port: 12345
mysql_db_host: 'baz-db.remote
mysql_db_dbs:
- 'bazdb1'
- 'bazdb2'
- 'bazdb3'
mysql_dump_local_destination: '/backups/baz/'
然后在任何地方创建以下剧本,我们称之为make_backup_dumps.yaml
:
---
- hosts: dbservers
become: false
tasks:
- name: Dump requested databases.
community.mysql.mysql_db:
login_host: '{{ mysql_db_host }}'
login_user: '{{ mysql_db_user }}'
login_port: '{{ mysql_db_port }}'
skip_lock_tables: true
state: dump
target: '/tmp/db_{{ ansible_host }}_{{ item }}.sql.gz'
loop: {{ mysql_db_dbs }}
- name: Retrieve remote dumps.
ansible.builtin.fetch:
src: '/tmp/db_{{ ansible_host }}_{{ item }}.sql.gz'
dest: '{{ mysql_dump_local_destination }}'
loop: {{ mysql_db_dbs }}
ansible-playbook --limit foo make_backup_dumps.yaml
使用;在一台主机上测试脚本如果输出符合您的喜好,请为所有带有ansible-playbook make_backup_dumps.yaml
.
这可能比单行代码有点笨重,但它的可读性更高,更容易维护,支持每个主机多个数据库表转储,将在每个主机上并行运行,并将为您提供每个主机上每个步骤的成功/失败的概述,并提供可选的详细级别,以便您可以排除故障。
是否使用它取决于你,但无论如何,出于对 GNU 的热爱,至少要清理你的主机密钥,因为你实际遇到的错误是本地引起的。