FROM ubuntu:18.04
# Set temp work directory
# for package configuration
WORKDIR /usr/src/cache
# Update apt packages RUN apt update RUN apt upgrade -y
# Install vim
RUN apt install vim -y
# Install python 3.7
RUN apt install software-properties-common -y
RUN add-apt-repository ppa:deadsnakes/ppa
RUN apt install python3.7 -y # Make python 3.7 the default
RUN echo "alias python=python3.7" >> ~/.bashrc
RUN export PATH=${PATH}:/usr/bin/python3.7
RUN /bin/bash -c "source ~/.bashrc"
# Install pip
RUN apt install python3-pip -y
RUN python -m pip install --upgrade pip
Category: Linux
Ubuntu18.04创建新的系统用户
useradd -r -m -s /bin/bash docker
参数说明:
-r:建立系统账号
-m:自动建立用户的登入目录
-s:指定用户登入后所使用的shell
passwd docker
ubuntu18 nvidia cuda tensorflow2.1 driver install
conda
wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/miniconda/Miniconda3-4.7.10-Linux-x86_64.sh
chmod 777 Miniconda3-4.7.10-Linux-x86_64.sh
./Miniconda3-4.7.10-Linux-x86_64.sh
conda create -n tf21 python=3.7
driver
sudo ubuntu-drivers devices
sudo apt install nvidia-driver-430
conda activate tf21
conda install cudatoolkit=10.1
conda install cudnn=7.6


HSTS
最近一直在测试 ingress 的 https 连接, 所以域名和证书频繁更换, 然后… 今天下午快被 HSTS 恶心死了
症状是换了证书或者地址之后, 浏览器认为是网站被劫持了
HSTS 会做什么呢? 在浏览器第一次访问了 www.bestofgit.com 之后, 如果此时连接被跳转到了https, 并且得到了HSTS的头标识, 那么支持HSTS的浏览器 ( 最新版的chrome ) , 会强制你的浏览器在下次访问的时候使用https连接这个网站 , 并且… 如果证书是不安全的 ( 自签名那种, 没有经过第三方认证的 ) , 那么恭喜你, 你会一直看到下面这个页面
一直到… 天荒地老 … 当然不是, 一直到 HSTS 头中定义的时间过去, 如果它定义了 1 年, 那么再次恭喜你, 跟天荒地老也差不多了

如何关闭这个功能呢? 首先我想到的是修改服务器, 但是仍然会看到这个页面, 只能去修改chrome
然后看到

在最下面的 delete 那里输入你的 域名 , 然后delete
Ansible 入门 5 (Ansible管理docker的容器)
YAML格式的playbook的属性包括
必要属性只有下面两个
host : 目标的一组主机
task : 需要执行的任务
可选的属性包括
name 其实是一段注释,用来标注这个play , 内容会被执行这个playbook的时候打印出来
sudo 如果设置为true , 运行task的时候会使用sudo命令切换root
vars 变量与值组成的列表
vars: server_name : myserver port : 22 |
– name : run taskshell : echo “{{server_name}}” |
task 是需要执行的任务列表
其中name属性是可选的,例如
– apt : name=nginx update_cache=yes
task支持一些模块, 常用的包括
shell, apt, copy , file , service, template, pip 等
Ansible 入门 4 (Ansible管理docker的容器)
上一章节我给出了一个简单的playbook
这一章节让我们来看看细节
playbook 是 YAML 格式的
YAML是”YAML Ain’t a Markup Language”(YAML不是一种置标语言)的递归缩写。
在开发的这种语言时,YAML 的意思其实是:”Yet Another Markup Language”(仍是一种置标语言)
YAML 文件应该以三个减号 — 开头, 不过你也可以忽略它, 不会带来任何问题
注释是通过 # , 和 shell 脚本一样
字符串文本也不需要使用 引号 括起来, 当然如果括起来可以, 即使中间包含空格也可以不用引号
hello world 这样的字符串完全可以识别正确
对于布尔类型的值十分灵活
如果一个值为”真” 可以使用
true, True , TRUE , yes, Yes, YES, on, On, ON , y ,Y
对应的如果一个值为 “假” 可以使用
false, False, FALSE, no, No, NO, off, Off, OFF, n, N
列表格式
如果你使用过json, json的列表格式是这样的
[ “hello”, “world”] |
YAML中列表使用 减号 “-” 分割列表
– hello- world |
第三节中我们使用了 – name: install 这样的描述
YAML中的 冒号 是用来表示 “字典” 的, 但是这个字典更像是 json中的对象, python中的字典
我们以一个python字典为例
{key1 : value1, key2 : value2 } |
对应的YAML是
key1: value1key2: value2 |
对于较长的内容, 大于号 > 标记 折行 , 而所有的换行符反而会被替换成空格
通过观察,你现在可以看出一个yaml文件的内容, 实际上就是 由字典元素组成的列表
– 列表
字典key1:字典value1
字典key2:字典value2
字典key3:
-key3的列表
key3列表里的key1:value1
每个play必需包含下面两项
- host
- task
host用于标示一组主机
task用于标示需要执行的任务
free命令的available
3.14内核新增了一个内存信息MemAvailable , 当调用free命令时可以显示为available
之前没留意过
[root@VM_167_46_centos etc]# free -h
total used free shared buff/cache available
Mem: 993M 253M 334M 39M 405M 556M
Swap: 2.0G 82M 1.9G
我们知道used + free + buff 基本等于 total
used是被使用的
free是完全没有被使用的
shared是被程序之间可以(已经被)共享使用的
buffers是指用来给块设备做的缓冲大小,它只记录文件系统的metadata以及 tracking in-flight pages
cached是用来给文件做缓冲
也就是 buffers是用来存储目录里面有什么内容,权限等等。而cached直接用来缓存我们打开的文件
available到底是什么
Many load balancing and workload placing programs check /proc/meminfo to estimate how much free memory is available. They generally do this by adding up “free” and “cached”, which was fine ten years ago, but is pretty much guaranteed to be wrong today.
It is wrong because Cached includes memory that is not freeable as page cache, for example shared memory segments, tmpfs, and ramfs, and it does not include reclaimable slab memory, which can take up a large fraction of system memory on mostly idle systems with lots of files.Currently, the amount of memory that is available for a new workload,without pushing the system into swap, can be estimated from MemFree, Active(file), Inactive(file), and SReclaimable, as well as the “low”watermarks from /proc/zoneinfo.However, this may change in the future, and user space really should not be expected to know kernel internals to come up with an estimate for the amount of free memory.It is more convenient to provide such an estimate in /proc/meminfo. If things change in the future, we only have to change it in one place.
也就是说available才是你的”可用内存” , 而不是像过去那样简单的把free和buffer加起来
available 小于 free+buffer 是一定的了
Ansible 入门 3 (Ansible管理docker的容器)
playbook 指的是用于配置管理的脚本, 实际上playbook才是ansible的重头戏
我将尝试使用一个playbook同时控制之前创建的3个虚拟机(docker 容器)
先看一个简单脚本
[root@vagrant playbooks]# vi hostname.yml
- name: call hostname
hosts: dockers
sudo: False
tasks:
- name: install
shell: hostname > /hostname.txt
直接调用
[root@vagrant playbooks]# ansible-playbook hostname.yml
PLAY [call hostname] **********************************************************
GATHERING FACTS ***************************************************************
ok: [172.17.0.4]
ok: [172.17.0.3]
ok: [172.17.0.2]
TASK: [install] ***************************************************************
changed: [172.17.0.3]
changed: [172.17.0.4]
changed: [172.17.0.2]
PLAY RECAP ********************************************************************
172.17.0.2 : ok=2 changed=1 unreachable=0 failed=0
172.17.0.3 : ok=2 changed=1 unreachable=0 failed=0
172.17.0.4 : ok=2 changed=1 unreachable=0 failed=0
检查一下结果

下面是一个安装httpd的脚本
[root@vagrant playbooks]# vi httpd.yml
- name: install httpd from yum
hosts: dockers
sudo: False
tasks:
- name: install
shell: yum install httpd
- name: start httpd
shell: /usr/sbin/httpd
调用 ansible-playbook ./playbooks/httpd.yml
可以看到log中
[root@vagrant log]# tail -500f ansible.log
2017-06-06 14:55:23,353 p=19632 u=root |
2017-06-06 14:55:23,354 p=19632 u=root | /usr/bin/ansible dockers -a hostname
2017-06-06 14:55:23,354 p=19632 u=root |
2017-06-06 14:55:25,190 p=19632 u=root | 172.17.0.3 | success | rc=0 >>
fd62f7fed827
2017-06-06 14:55:25,195 p=19632 u=root | 172.17.0.2 | success | rc=0 >>
86b87edef2cd
2017-06-06 14:55:25,195 p=19632 u=root | 172.17.0.4 | success | rc=0 >>
7c6125cedfd3
2017-06-06 15:43:02,383 p=21343 u=root |
2017-06-06 15:43:02,384 p=21343 u=root | /usr/bin/ansible-playbook ./playbooks/httpd.yml
2017-06-06 15:43:02,384 p=21343 u=root |
2017-06-06 15:43:02,387 p=21343 u=root | ERROR: Syntax Error while loading YAML script, ./playbooks/httpd.yml
Note: The error may actually appear before this position: line 6, column 5
- name: install
shell: yum install httpd
^
2017-06-06 15:45:22,766 p=21408 u=root |
2017-06-06 15:45:22,766 p=21408 u=root | /usr/bin/ansible-playbook ./playbooks/httpd.yml
2017-06-06 15:45:22,766 p=21408 u=root |
2017-06-06 15:45:22,795 p=21408 u=root | PLAY [install httpd from yum] *************************************************
2017-06-06 15:45:22,795 p=21408 u=root | GATHERING FACTS ***************************************************************
2017-06-06 15:45:24,231 p=21408 u=root | failed: [172.17.0.4] => {"failed": true, "parsed": false}
2017-06-06 15:45:24,232 p=21408 u=root | /bin/sh: sudo: command not found
OpenSSH_6.6.1, OpenSSL 1.0.1e-fips 11 Feb 2013
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 56: Applying options for *
debug1: auto-mux: Trying existing master
debug1: mux_client_request_session: master session id: 2
Shared connection to 172.17.0.4 closed.
2017-06-06 15:45:24,235 p=21408 u=root | failed: [172.17.0.3] => {"failed": true, "parsed": false}
2017-06-06 15:45:24,235 p=21408 u=root | /bin/sh: sudo: command not found
OpenSSH_6.6.1, OpenSSL 1.0.1e-fips 11 Feb 2013
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 56: Applying options for *
debug1: auto-mux: Trying existing master
debug1: mux_client_request_session: master session id: 2
Shared connection to 172.17.0.3 closed.
2017-06-06 15:45:24,240 p=21408 u=root | failed: [172.17.0.2] => {"failed": true, "parsed": false}
2017-06-06 15:45:24,240 p=21408 u=root | /bin/sh: sudo: command not found
OpenSSH_6.6.1, OpenSSL 1.0.1e-fips 11 Feb 2013
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 56: Applying options for *
debug1: auto-mux: Trying existing master
debug1: mux_client_request_session: master session id: 2
Shared connection to 172.17.0.2 closed.
2017-06-06 15:45:24,249 p=21408 u=root | TASK: [install] ***************************************************************
2017-06-06 15:45:24,255 p=21408 u=root | FATAL: no hosts matched or all hosts have already failed -- aborting
2017-06-06 15:45:24,255 p=21408 u=root | PLAY RECAP ********************************************************************
2017-06-06 15:45:24,256 p=21408 u=root | to retry, use: --limit @/root/httpd.retry
2017-06-06 15:45:24,256 p=21408 u=root | 172.17.0.2 : ok=0 changed=0 unreachable=0 failed=1
2017-06-06 15:45:24,256 p=21408 u=root | 172.17.0.3 : ok=0 changed=0 unreachable=0 failed=1
2017-06-06 15:45:24,256 p=21408 u=root | 172.17.0.4 : ok=0 changed=0 unreachable=0 failed=1
2017-06-06 15:45:53,254 p=21584 u=root |
2017-06-06 15:45:53,254 p=21584 u=root | /usr/bin/ansible-playbook ./playbooks/httpd.yml
2017-06-06 15:45:53,254 p=21584 u=root |
2017-06-06 15:45:53,269 p=21584 u=root | PLAY [install httpd from yum] *************************************************
2017-06-06 15:45:53,270 p=21584 u=root | GATHERING FACTS ***************************************************************
2017-06-06 15:45:55,102 p=21584 u=root | ok: [172.17.0.2]
2017-06-06 15:45:55,107 p=21584 u=root | ok: [172.17.0.4]
2017-06-06 15:45:55,134 p=21584 u=root | ok: [172.17.0.3]
2017-06-06 15:45:55,144 p=21584 u=root | TASK: [install] ***************************************************************
由于网络问题这里我等待的时间太长了,所以直接中断了 🙁
Ansible 入门 2 (Ansible管理docker的容器)
对于上一章节中我们提到的 /etc/ansible/hosts 配置文件可以通过 -i 参数指定, 如果不指定默认查找/etc/ansible/hosts 路径
ansible dockers -a “hostname”
等价于
ansible -i /etc/ansible/hosts dockers -a “hostname”
在这个hosts文件中还可以通过 ansible_ssh_host和ansible_ssh_port 单独指定目标机器的ip和端口
下面是这次的重点, 如果你需要多个hosts文件的话,你需要使用ansible.cfg文件
这个文件可以用来配置一些默认值
Ansible 按照如下 位置和顺序 来查找 ansible.cfg
1. ANSIBLE_CONFIG 环境变量指定的文件
2. ./ansible.cfg 当前工作目录下的文件
3. ~/.ansible.cfg 用户home路径下的文件
4. /etc/ansible/ansible.cfg 目录下的文件
这里我创建一个/ansible目录作为工作目录
[defaults] inventory=/ansible/config/hosts log_path=/ansible/log/ansible.log |
然后在/ansible/config/hosts创建一个hosts文件
直接调用出现了错误
[root@vagrant ansible]# ansible dockers -a "hostname"
Traceback (most recent call last):
File "/usr/bin/ansible", line 36, in <module>
from ansible.runner import Runner
File "/usr/lib/python2.7/site-packages/ansible/runner/__init__.py", line 37, in <module>
import ansible.inventory
File "/usr/lib/python2.7/site-packages/ansible/inventory/__init__.py", line 26, in <module>
from ansible.inventory.ini import InventoryParser
File "/usr/lib/python2.7/site-packages/ansible/inventory/ini.py", line 21, in <module>
from ansible.inventory.host import Host
File "/usr/lib/python2.7/site-packages/ansible/inventory/host.py", line 19, in <module>
from ansible import utils
File "/usr/lib/python2.7/site-packages/ansible/utils/__init__.py", line 29, in <module>
from ansible.utils.display_functions import *
File "/usr/lib/python2.7/site-packages/ansible/utils/display_functions.py", line 22, in <module>
from ansible.callbacks import display
File "/usr/lib/python2.7/site-packages/ansible/callbacks.py", line 42, in <module>
logging.basicConfig(filename=path, level=logging.DEBUG, format='%(asctime)s %(name)s %(message)s')
File "/usr/lib64/python2.7/logging/__init__.py", line 1529, in basicConfig
hdlr = FileHandler(filename, mode)
File "/usr/lib64/python2.7/logging/__init__.py", line 902, in __init__
StreamHandler.__init__(self, self._open())
File "/usr/lib64/python2.7/logging/__init__.py", line 925, in _open
stream = open(self.baseFilename, self.mode)
IOError: [Errno 2] No such file or directory: '/ansible/log/ansible.log'
原来这家伙笨到不会自己创建文件夹
mkdir /ansible/log 之后工作正常

Ansible 入门 1 (Ansible管理docker的容器)
安装 yum -y install ansible 或者 pip install ansible
需要把托管机的ip加入到hosts文件里
/etc/ansible/hosts
这里我只做个单机测试,使用用户名密码登录,我使用root用户, 尝试让ansible使用vagrant用户
使用用户名密码的话还需要安装 yum install sshpass
[web] 172.28.128.4 ansible_ssh_user=vagrant ansible_ssh_pass=vagrant |
运行
[root@vagrant ansible]# ansible web -a “hostname” 172.28.128.4 | success | rc=0 >> vagrant |
秘钥登录的话直接去掉ansible_ssh_pass参数就可以了,当然你需要先提供免密码登录
可以参考http://lizhe.name.csdn.net/node/24里的免密码登录
如果是机器A登录到机器B, 在A上生成秘钥对 ssh-keygen -t rsa -P ”
将机器A上的 公钥 复制到机器B , 内容直接cat给 .ssh/authorzied_keys
记得确认/etc/ssh/sshd_config 中的key文件位置和文件名
/root/.ssh/id_rsa
/root/.ssh/id_rsa.pub
ansible默认使用5个线程执行, 如果需要指定线程数需要使用 -f 参数
[root@vagrant ansible]# ansible web -a “hostname” -f 1 172.28.128.4 | success | rc=0 >> vagrant |
上面的例子实际上使用了 command 模块,这个模块是默认提供的,它接收 -a 参数提供的命令,所以下面两行命令实际上是等价的
ansible web -a “hostname”
ansible web -m command -a “hostname”
这里我决定还是请出我们的老朋友, docker和它的容器们
docker run -t -i –name ansible_vm_1 docker.io/centos /bin/bash
docker run -t -i –name ansible_vm_2 docker.io/centos /bin/bash
docker run -t -i –name ansible_vm_3 docker.io/centos /bin/bash
创建了3个容器

虽然docker不鼓励使用ssh登录进容器,也不鼓励修改容器用户的密码, 但是这里实在不想做一遍免密登录了,所以打算直接用用户名密码登录容器, 因为ansible是基于ssh的,所以还是要去给容器安装一下sshd服务
yum -y install openssh-server openssh-clients
/etc/ssh/sshd_config 文件中打开root用户远程登录 PermitRootLogin yes
修改完之后手动启动sshd服务 /usr/sbin/sshd
如果出现找不到key的错误
[root@7c6125cedfd3 /]# /usr/sbin/sshd
Could not load host key: /etc/ssh/ssh_host_rsa_key
Could not load host key: /etc/ssh/ssh_host_dsa_key
Could not load host key: /etc/ssh/ssh_host_ecdsa_key
Could not load host key: /etc/ssh/ssh_host_ed25519_key
把其他的key注释掉,保留一个rsa_key 然后使用ssh-keygen -t rsa -b 2048 -f /etc/ssh/ssh_host_rsa_key 重新生成一个就行了
passwd root改个密码
把三个容器都配置完成以后在宿主机上尝试添加这3个容器
查看一下容器ip
docker inspect -f ‘{{.NetworkSettings.IPAddress}}’ ansible_vm_1

把ip加进ansible的配置文件里 /etc/ansible/hosts
[dockers] 172.17.0.2 ansible_ssh_user=root ansible_ssh_pass=root 172.17.0.3 ansible_ssh_user=root ansible_ssh_pass=root 172.17.0.4 ansible_ssh_user=root ansible_ssh_pass=root |

要屏蔽第一次连接出现yes/no的情况
/etc/ansible/ansible.cfg
# uncomment this to disable SSH key host checking
host_key_checking = False