Big Little Ant

不被嘲笑的梦想,是不值得去实现的

SLS是Salt State系统的核心,用来描述系统的目标状态,使用YAML语言书写。被用作配置文件管理。

SLS文件

sls配置文件分为两种类型

  • top.sls 这是所有配置文件的入口
  • sls 这是每个不同的配置文件

top.sls

  • top.sls 文件是其他sls文件的起始位置,使用salt '*' state.highstate调用。
  • top.sls 文件的位置:master文件中base环境定义的文件夹下。
  • 假设base路径为:/srv/salt/base 则top文件路径:/srv/salt/base/top.sls

top.sls 文件格式如下:

1
2
3
4
5
6
7
8
9
10
11
12
base: ## 从哪里开始读取配置文件,可以是base,prod等,
'os:centos': ## 目标主机
- match: grain ## match 匹配方式,
- init.env_init ## 需要执行的什么命令
- zabbix-agent-linux.config
- salt.agent

prod:
'blog.*.(service|mongodb|proxydb)':
- match: pcre
- publish.config
- filebeat.config

解释:

  • top文件遵循YAML语法,不同的层级用不同的空格定义。
  • base:表示文件的其实位置。
  • ‘os:centos’ :表示目标主机。
  • match:
  • grain: 按照grains规则去匹配
  • nodegroup: 按照分组名进行匹配
  • pcre: 正则匹配
  • 如果不写match行,则默认使用通配符匹配。

sls文件编写方法

1
2
3
4
5
6
7
8
agent-config:  ##定义一个名称
file.managed: ## 定义一个方法
- name: /etc/salt/minion ##定义方法需要的相关参数
- source: salt://salt/files/minion-config
- user: root
- group: root
- mode: 644
- template: jinja ##启用jinja模板匹配

简写方法:

vim /srv/salt/apache/install.sls

1
2
3
apache:                 # 定义名称
pkg: # 定义函数
- installed # 定义方法

简版的语法与上面的语法一致,区别在于可以将名称写在行首。这样就不用定义方法名称了。

最后执行 salt '*' state.highstate test=True测试编写的文件是否正常。结果正常,则去掉test=True正式执行。

sls编写方法注意事项

1
2
3
4
5
6
7
8
9
10
11
12
13
include:
apache.install

agent-config:
file.managed:
- name: /etc/salt/minion
- source: salt://salt/files/minion-config
- user: root
- group: root
- mode: 644
- template: jinja
- require:
- pkg: apache
1
2
include:
apache.install

include可以把已经写好的文件包含进来一起执行。

一个agent-config代表一个命名空间,一个命名空间内只有有一种方法即file.managed方法只能出现一次。
如果写多个file.managed就需要使用不用的命名空间。

- template: jinja 表示配置文件中定义了jinja模板。

jinja模板语法:

1
2
3
{% for i in ['/etc/','/usr']%}
touch {{ i }}/1.txt
{% endfor %}
1
2
3
4
5
6
7
8
httpd:
pkg.managed:
{% if grains['os'] == 'Ubuntu' %}
- name: apache2
{% elif grains['os'] == 'CentOS' %}
- name: httpd
{% endif %}
- installed

set 这是jinja模板的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{% set site_user = 'testuser' %}
{% set site_name = 'test_site' %}
{% set project_name = 'test_proj' %}
{% set sites_dir = 'test_dir' %}

django-project:
file.recurse:
- name: {{ sites_dir }}/{{ site_name }}/{{ project_name }}
- user: {{ site_user }}
- dir_mode: 2775
- file_mode: '0644'
- template: jinja
- source: salt://project/templates_dir
- include_empty: True

- require表示依赖,Apache表示命名空间,pkg表示命名空间中的某一个方法。

1
2
- require:
- pkg: apache

其他配置

  • watch: 监控状态是否变化,常用在service.running中。
  • last:想让某个state最后一个运行,可以用last。
  • order:优先级比require和watch低,有order指定的state比没有order指定的优先级高。
1
2
3
vim:
pkg.installed:
- order: 1

saltstack 常用模块介绍

file模块

被控主机文件常见操作,包括文件读写、权限、查找、校验等

salt '*' file.get_sum /etc/resolv.conf md5
salt '*' file.stats /etc/resolv.conf

file.managed-文件管理

先来一个实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/etc/http/conf/http.conf:
file.managed:
- source: salt://apache/http.conf
- user: root
- group: root
- mode: 644
- template: jinja
- defaults:
custom_var: "default value"
other_var: 123
{% if grains['os'] == 'Ubuntu' %}
- context:
custom_var: "override"
{% endif %}

source-指定源文件

source参数可以作为一个列表指定。如果这样做的话,那么会使用第一个匹配到的文件。这个特性允许你如果请求的文件不存在于salt文件服务器时有一个默认的文件回溯。

1
2
3
4
5
6
7
8
9
/etc/foo.conf:
file.managed:
- source:
- salt://foo.conf.{{ grains['fqdn'] }}
- salt://foo.conf.fallback
- user: foo
- group: users
- mode: 644
- backup: minion

source 参数同样可以指定一个在另一个Salt环境的文件。在这个例子中 foo.conf 将会使用 dev 环境中的来替代。

1
2
3
4
5
6
7
/etc/foo.conf:
file.managed:
- source:
- salt://foo.conf?saltenv=dev
- user: foo
- group: users
- mode: '0644'

file.directory-目录管理

1
2
3
4
5
6
/srv/stuff/substuf:
file.directory:
- user: fred
- group: users
- mode: 755
- makedirs: True

使用 dir_mode 和 file_mode,同时指定目录和文件的权限。

1
2
3
4
5
6
7
8
9
10
11
/srv/stuff/substuf:
file.directory:
- user: fred
- group: users
- file_mode: 744
- dir_mode: 755
- makedirs: True
- recurse:
- user
- group
- mode

file.recurse - 递归目录

1
2
3
4
/opt/code/flask:
file.recurse:
- source: salt://code/flask
- include_empty: True
1
2
3
/etc/grub.conf:
file.symlink:
- target: /boot/grub/grub.conf

file.append - 文件后面追加内容

1
2
3
4
5
/etc/motd:
file.append:
- text:
- Trust no one unless you have eaten much salt with him.
- "Salt is born of the purest of parents: the sun and the sea."

官方帮助文档:https://docs.saltstack.com/en/latest/ref/states/all/salt.states.file.html

cmd模块

实现远程的命令行调用执行

run-执行命令

salt '*' cmd.run 'ss -lntup'

cmd模块执行windows命令

salt '*' cmd.run 'dir' shell=powershell

1
2
3
4
5
6
7
8
getpip:
cmd.run:
- name: /usr/bin/python /usr/local/sbin/get-pip.py
- unless: which pip
- require:
- pkg: python
- file: /usr/local/sbin/get-pip.py
- reload_modules: True

script-执行脚本

1
2
3
salt://scripts/bar.sh:
cmd.script:
- env: "PATH=/some/path:$PATH"

pkg包管理模块

installed - 安装包

1
2
3
4
5
6
7
8
php.packages:
pkg.installed:
- fromrepo: wheezy-php55
- pkgs:
- php5-fpm
- php5-cli
- php5-curl
- bar: '>=1.2.3-4'

也可以指定安装包的位置

1
2
3
4
5
6
7
mypkgs:
pkg.installed:
- sources:
- foo: salt://rpms/foo.rpm
- bar: http://somesite.org/bar.rpm
- baz: ftp://someothersite.org/baz.rpm
- qux: /minion/path/to/qux.rpm

命令行的方式安装包

salt '*' pkg.install nmap
salt '*' pkg.file_list nmap

service 服务模块

running 配置服务启动

1
2
3
4
5
6
redis:
service.running:
- enable: True
- reload: True
- watch:
- pkg: redis

reloadwatch一起使用,watch监控到服务的变化,reload会自动重载服务。

dead 停止服务

1
2
3
redis:
service.dead:
- enable: True

确定redis服务已经停止,并加入开机自启动。

shell端执行命令

使sshd加入开机自启动
salt '*' service.enable sshd

使sshd加入开机自启动
salt '*' service.disable sshd

查看sshd的状态
salt '*' service.status sshd

停止sshd服务
salt '*' service.stop sshd

启动sshd服务
salt '*' service.start sshd

重启sshd服务
salt '*' service.restart sshd

重载sshd服务
salt '*' service.reload sshd

useradd用户模块

absent - 删除用户

1
2
3
4
nginx:
user.present:
- purge: True
- force: True

purge: 清楚用户家目录
force: 即使用户登录,也要删除用户(默认用户登录时,清除会失败)。

present - 创建用户

一、添加单个用户:
生成密码

1
2
3
openssl passwd -1 -salt 'nginx'
Password:
$1$nginx$LrLRyngZUF2qJ8f3a31cN0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
nginx:
user.present:
- fullname: nginx web
- shell: /bin/bash
- password: '$1$nginx$LrLRyngZUF2qJ8f3a31cN0'
- home: /home/nginx
- uid: 1000
- gid: 1000
- groups:
- nginx
- require:
- group: nginx
group.present:
- gid: 1000

创建一个不能登录,没有家目录的用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
nginx:
user.present:
- fullname: nginx web
- shell: /sbin/nologin
- password: '$1$nginx$LrLRyngZUF2qJ8f3a31cN0'
- createhome: False
- uid: 1000
- gid: 1000
- groups:
- nginx
- require:
- group: nginx
group.present:
- gid: 1000

gid_from_name: 如果设置为_True_,默认的组id将自动设置为和本用户同名的组id
groups: 分配给该用户的组列表(a list of groups). 如果组在minion上不存在,则本state会报错. 如果设置会空,将会删除本用户所属的除了默认组之外的其他组
optional_groups: 分配给用户的组列表。 如果组在minion上不存在,则state会忽略它.

配合jinja模板批量添加多个用户

1
2
3
4
5
6
7
8
9
{{ set userlist=['big','little','ant'] }}
{% for user in userlist %}
{{ user }}:
user.present:
- fullname: {{ user }} web
- shell: /sbin/nologin
- password: '$1$nginx$LrLRyngZUF2qJ8f3a31cN0'
- createhome: False
{% endfor %}

cp模块

实现远程文件、目录的复制,以及下载URL文件等操作

将主服务器file_roots指定位置下的目录复制到被控主机
salt 'chuye.backup*' cp.get_dir salt://iis-works/files/ /tmp/

将主服务器file_roots指定位置下的文件复制到被控主机
salt 'chuye.backup*' cp.get_file salt://iis-works/files/web-config /tmp/

下载指定URL内容到被控主机指定位置
salt '*' cp.get_url http://xxx.xyz.com/download/0/files.tgz /root/files.tgz

cron模块

present - 管理crontab

实现被控主机的crontab操作

1
2
3
4
date > /tmp/crontest:
cron.present:
- user: root
- minute: '*/5'
1
2
3
4
5
6
superscript > /tmp/crontest:
cron.present:
- identifier: SUPERCRON
- user: root
- minute: 3
- hour: 4

identifier:文件的标示,默认是状态ID。

file - 为crontab提供类似文件管理的功能

1
2
3
4
5
foo_crontab:
cron.file:
- name: https://mydomain.tld/dir2/foo.txt
- source_hash: https://mydomain.tld/hashes
- source_hash_name: ./dir2/foo.txt

命令行执行

查看指定主机某用户的crontab
salt '*' cron.raw_cron root

为指定的被控主机、root用户添加crontab信息
salt '*' cron.set_job root '*/5' '*' '*' '*' '*' 'date >/dev/null 2>&1'

删除指定的被控主机、root用户的crontab信息
salt '*' cron.rm_job root 'date >/dev/null 2>&1'

dnsutil模块

实现被控主机通用DNS操作

为被控主机添加指定的hosts主机配置项
salt '*' dnsutil.hosts_append /etc/hosts 192.168.56.12 linux-node2

network模块

返回被控主机网络信息
salt '*' network.ip_addrs

salt '*' network.interfaces

参考链接

state modules

execution modules

saltstack简介

SaltStack是一种新型的基础设施管理软件,简单易部署,可伸缩的足以管理成千上万的服务器,和足够快的速度控制,与他们交流,以毫秒为单位。SaltStack提供了一个动态基础设施通信总线用于编排,远程执行、配置管理等等。SaltStack项目于2011年启动,年增长速度较快,五年期固定基础设施编制和配置管理的开源项目。SaltStack社区致力于保持slat项目集中、友好、健康、开放。

简单来说它的两大基础功能就是:配置管理、远程命令执行。剩下就是根据你的需求自由组合,实现更复杂的功能和系统管理

saltstack运行的模式

1:local
2:master/minion
3:salt SSH(可以不依赖客户端)

saltstack三大功能

远程执行
配置管理
云管理(不是特别成熟,不建议生产环境使用)
Salt即可以批量执行命令,也可以单机执行。通常单机执行用于测试:

  1. 单机(立即)执行。 使用salt-call命令单机执行操作
  2. 批量(立即)执行。最常用的操作。使用salt命令,对匹配的minion节点执行操作

saltstack安装实战

salt解析基于DNS,如果做实验发现执行特别慢,可以尝试配置好域名解析.

服务器安装

salt-master可以使用两个源来安装,一个是EPEL源,一个salt的官方源。
推荐使用salt的官方源。

安装epel包

1
2
rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-6.noarch.rpm
rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm

配置saltstack的官方yum源

centos 7:

1
2
3
4
5
6
7
8
9
vim /etc/yum.repo.d/saltstack-repo
####################
# Enable SaltStack's package repository
[saltstack-repo]
name=SaltStack repo for RHEL/CentOS 7
baseurl=https://repo.saltstack.com/yum/rhel7
enabled=1
gpgcheck=0
gpgkey=https://repo.saltstack.com/yum/rhel7/SALTSTACK-GPG-KEY.pub

centos6

1
2
3
4
5
6
7
8
9
vim /etc/yum.repo.d/saltstack-repo
####################
# Enable SaltStack's package repository
[saltstack-repo]
name=SaltStack repo for RHEL/CentOS 6
baseurl=https://repo.saltstack.com/yum/rhel6
enabled=1
gpgcheck=0
gpgkey=https://repo.saltstack.com/yum/rhel6/SALTSTACK-GPG-KEY.pub

服务端安装salt-master 软件并启动

1
2
3
yum install salt-master -y
[root@centos6 ~]# /etc/init.d/salt-master start
Starting salt-master daemon: [ OK ]

配置saltstack服务端如下内容:

配置文件需要顶头写,不能有空格。
vim /etc/salt/master

原内容:

1
2
3
4
5
6
7
8
9
10
11
12
#default_include: master.d/*.conf
#interface: 0.0.0.0
# file_roots:
# base:
# - /srv/salt/
# dev:
# - /srv/salt/dev/services
# - /srv/salt/dev/states
# prod:
# - /srv/salt/prod/services
# - /srv/salt/prod/states

修改后的文件:

1
2
3
4
5
6
7
8
default_include: master.d/*.conf
interface: 0.0.0.0
file_roots:
base:
- /etc/salt/states
prod:
- /etc/salt/states/prod
[root@centos6 ~]# mkdir /etc/salt/states/prod -p

修改完配置文件后,需要重启服务

1
2
3
[root@centos6 ~]# /etc/init.d/salt-master restart
Stopping salt-master daemon: [ OK ]
Starting salt-master daemon: [ OK ]

注意:salt的书写一定要注意格式。基础环境(base),生产环境(prod),测试环境(test)分三个目录。通过不同的目录创建不同的内容。

关于salt-master配置文件更多的内容可以参考salt配置文件详解

补充一个线上的配置文件

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
interface: 192.168.56.11
ipv6: False
max_open_files: 65535
worker_threads: 5
timeout: 30
state_verbose: False
file_roots:
base:
- /data/salt/base
prod:
- /data/salt/prod
config:
- /data/salt/config
linux:
- /data/salt/linux
log_file: /var/log/salt/master
log_level_logfile: debug
mysql.host: '192.168.56.13'
mysql.user: 'salt'
mysql.pass: '123456'
mysql.db: 'salt'
mysql.port: 3306
external_auth:
pam:
saltapi:
- .*
- '@runner'
- '@jobs'
rest_cherrypy:
port: 8088
ssl_crt: /etc/pki/tls/certs/localhost.crt
ssl_key: /etc/pki/tls/private/localhost_nopass.key

客户端安装方法:

安装salt-minion 软件

1
yum install salt-minion -y

配置并启动saltstack客户端。

1
2
3
4
[root@centos6 ~]# cd /etc/salt/
[root@centos6 salt]# vim minion
master: 192.168.56.11
id: minion.saltstack.com

重启minion进程

1
2
3
4
5
6
[root@centos6 salt]# /etc/init.d/salt-minion start
Starting salt-minion daemon: [ OK ]

[root@centos6 salt]# /etc/init.d/salt-minion restart
Stopping salt-minion daemon: [ OK ]
Starting salt-minion daemon: [ OK ]

ID 存放在这个文件中

1
2
[root@data-1-1 salt]# cat /etc/salt/minion_id
data-1-1

删除旧的key文件

1
[root@centos6 salt]# mv minion_id /tmp/

master的key存放位置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# cd /etc/salt/pki/master/
# tree
+-- master.pem
+-- master.pub
+-- minions
| +-- linux-node1 (minion的公钥)
| +-- linux-node2 (minion的公钥)
+-- minions_autosign
+-- minions_denied
+-- minions_pre
+-- minions_rejected

5 directories, 4 files
[root@linux-node1 master]#

master端修改minion端的key名称

1
2
3
4
5
6
7
8
9
10
[root@linux-node1 minions]# mv linux-node1 linux-node3
[root@linux-node1 minions]# ls
linux-node2 linux-node3
[root@linux-node1 minions]# salt-key -L
Accepted Keys:
linux-node2
linux-node3
Denied Keys:
Unaccepted Keys:
Rejected Keys:

salt-key命令补充

  • salt-key -d www.etiantian.org 删除一个key 。
  • salt-key -A 同意所有未注册的minion端。
  • salt-key -a www.etiantian.org 同意一个机器。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@centos6 ~]# salt-key
Accepted Keys:
Denied Keys:
Unaccepted Keys:
centos6.6-mupan
minion.saltstack.com
Rejected Keys:
[root@centos6 ~]# salt-key -a minion.saltstack.com ####允许客户端连入服务器。
The following keys are going to be accepted:
Unaccepted Keys:
minion.saltstack.com
Proceed? [n/Y] y
Key for minion minion.saltstack.com accepted.
[root@centos6 ~]#

salt-stakck 状态查询

  • 查看还在运行的程序:salt-run jobs.active
  • 查看以前的操作历史记录来:salt-run jobs.list_jobs
  • 查看minion支持的module列表的命令 salt '*' sys.list_modules
  • 查看CMD模块下的所有function。salt '*' sys.list_functions cmd
  • 查看cmd 模块的详细用法。salt '*' sys.doc cmd

salt远程执行

命令格式:salt 'Trgetiong' module

  • 目标:Trgetiong
  • 模块:Module
  • 返回:Returners

目标匹配方式

通配符使用:

1
2
3
4
5
6
7
salt '*' test.ping
salt '*.example.net' test.ping
salt '*.example.*' test.ping
salt 'web?.example.net' test.ping
salt 'web[1-5]' test.ping
salt 'web[1,3]' test.ping
salt 'web-[x-z]' test.ping

正则表达式使用:

1
salt -E 'web1-(prod|devel)' test.ping

也可以在top.sls中使用正则表示:

1
2
3
4
base:
'web1-(prod|devel)':
- match: pcre
- webserver

lists使用:

1
salt -L 'web1,web2,web3' test.ping

IP地址使用:

1
2
3
[root@centos6 ~]# salt -S '192.168.2.0/24' test.ping
minion.saltstack.com:
True

Grains使用:

1
salt -G 'os:centos' test.ping

也可以在top.sls中使用Grains表示:

1
2
3
4
5
6
base:
'os:centos':
- match: grain
- init.env_init
- zabbix-agent-linux.config
- salt.agent

Pillar使用:

1
salt -I 'master:True' test.ping

salt 异步执行方法

1
2
3
4
5
[root@xxx ~]# salt --async test01 cmd.run "echo 'test'"
Executed command with job ID: 20150915151813222323
[root@xxx ~]# salt-run jobs.lookup_jid 20150915151813222323
Fabric:
test

还有个-v参数在返回结果的同时,一同返回本次任务的jid,如果超时还是会返回jid的。

1
2
3
4
5
[root@test ~]# salt -v test01 test.ping
Executing job with jid 20150917172323566343
-------------------------------------------
test01:
True

如果是调用saltapi来实现异步执行语句和获取jid信息,参数可以这样:

1
2
params = {'client':'local_async', 'fun':'test.echo', 'tgt':'test01', 'arg1':'hello'}
params = {'client':'runner', 'fun':'jobs.lookup_jid', 'jid': '20150827163231404925'}

salt权限控制

salt 使用 pam 模块对普通账号进行权限控制

salt 扩展认证 PAM,可以利用PAM 认证机制对系统账户做出功能操作上的限制。依赖的模块salt.states.external_auth

开启PAM认证

编辑 /etc/salt/master

1
2
3
4
external_auth:
pam:
salt:
- '*'

创建 salt 用户 设置密码

验证

salt PAM 认证用户 只能通过-a pam 参数才能使用

1
salt -a pam test.ping

会提示登陆用户,输入密码,如果正确返回结果,说明pam认证已经生效

实例 :

1
2
3
4
5
6
7
8
9
10
11
12
/etc/salt/master

external_auth:
pam:
admin:
- '*' # 所有模块
salt:
- test.ping # test.ping 模块
test:
- 'dev*' # 主机配置规则
- test.ping # Salt 模块

解释:

  • admin 用户可管理所有主机,使用所有salt功能模块
  • salt 用户可管理所有主机,仅能使用test.ping模块
  • test 用户只能管理部分主机,仅能使用test.ping模块

实例1: 以salt用户为例,认证用户必须打开PAM 参数才能操作

失败操作:

1
2
 salt '*' test.ping
Failed to authenticate, is this user permitted to execute commands?

成功操作:

1
2
3
4
5
 salt -a pam '*' test.ping
username: salt
password:
ubuntu-master:
True

实例2: 以salt用户为例,执行未授权模块被拒绝

1
2
3
4
salt -a pam '*' state.highstate
username: salt
password:
Failed to authenticate, is this user permitted to execute commands?

以test用户为例,操作未授权主机被拒绝
失败操作

1
2
3
4
salt -a pam '*' test
username: test
password:
Failed to authenticate, is this user permitted to execute commands?

成功操作

1
2
3
4
5
salt -a pam 'test-001' test
username: test
password:
test-001:
True

支持文档:

官方帮助文档
官方github
saltstack 中文用户组
Saltstack SLS文件解读
[官方的 salt-states 仓库地址] (https://github.com/saltstack/salt-states)

来自于社区的一些salt states例子:

https://github.com/blast-hardcheese/blast-salt-states
https://github.com/kevingranade/kevingranade-salt-state
https://github.com/uggedal/states
https://github.com/mattmcclean/salt-openstack/tree/master/salt
https://github.com/rentalita/ubuntu-setup/
https://github.com/brutasse/states
https://github.com/bclermont/states
https://github.com/pcrews/salt-data

参考文档
文档: http://docs.saltstack.com/topics/tutorials/starting_states.html
文档: http://docs.saltstack.com/ref/states/writing.html
文档: http://docs.saltstack.com/ref/states/ordering.html
文档: http://www.ituring.com.cn/article/37783
文档: http://docs.saltstack.com/topics/tutorials/starting_states.html

问题汇总:

报错一:

1
2
3
4
5
6
7
8
9
10
----------
ID: limit-conf-config
Function: file.managed
Name: /etc/securilty/limits.conf
Result: False
Comment: Parent directory not present
Started: 17:05:44.606040
Duration: 11.448 ms
Changes:

解决办法:

出现这个的原因是Minion上没有name参数定义的目录. 在minion上定义对应的目录就可以了

报错:salt 管理配置文件时,报错。

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
[root@master files]# salt '*' state.highstate
agent.niu.com:
Data failed to compile:
----------
Rendering SLS init.limit failed, render error: expected '<document start>', but found '<block mapping start>'
in "<unicode string>", line 2, column 1:
limit-conf-config:
^
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/salt/state.py", line 2509, in render_state
sls, rendered_sls=mods
File "/usr/lib/python2.7/site-packages/salt/template.py", line 79, in compile_template
ret = render(input_data, saltenv, sls, **render_kwargs)
▽ File "/usr/lib/python2.7/site-packages/salt/renderers/yaml.py", line 50, in render
data = load(yaml_data, Loader=get_yaml_loader(argline))
File "/usr/lib64/python2.7/site-packages/yaml/__init__.py", line 71, in load
return loader.get_single_data()
File "/usr/lib64/python2.7/site-packages/yaml/constructor.py", line 37, in get_single_data
node = self.get_single_node()
File "/usr/lib64/python2.7/site-packages/yaml/composer.py", line 39, in get_single_node
if not self.check_event(StreamEndEvent):
File "/usr/lib64/python2.7/site-packages/yaml/parser.py", line 98, in check_event
self.current_event = self.state()
File "/usr/lib64/python2.7/site-packages/yaml/parser.py", line 174, in parse_document_start
self.peek_token().start_mark)
ParserError: expected '<document start>', but found '<block mapping start>'
in "<unicode string>", line 2, column 1:
limit-conf-config:
^

解决办法:

配置文件的路径配置错误。导致报错。修改配置文件,问题解决。

报错:saltstack 执行后CPU占用率为百分之百。

1
2
[root@10-10-121-200 ~]# salt 'linux-backup-saltminion' test.ping
Salt request timed out. The master is not responding. If this error persists after verifying the master is up, worker_threads may need to be increased.

解决办法:

使用top 查看CPU占用率为百分之百。
降低salt的线程数。

报错:配置完return后,不能向数据库写入数据:

1
2
mysql> select * from salt_returns;
Empty set (0.00 sec)

解决思路:

当遇到问题是可以将log的级别更改为debug模式来调试。

解决办法:

因为是客户端直接返回给数据库,所有客户端需要数据库的连接权限。顾所有数据库都需要添加如下内容:

1
2
3
4
5
6
7
8
9
10
11
vim /etc/salt/minion
mysql.host: '192.168.2.150'
mysql.user: 'salt'
mysql.pass: 'salt'
mysql.db: 'salt'
mysql.port: 3306
[root@centos6 ~]# /etc/init.d/salt-minion restart
Stopping salt-minion daemon: [ OK ]
Starting salt-minion daemon: [ OK ]
[root@centos6 ~]#

报错: 执行state.sls 报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
root@10.10.121.200 files]# salt '*.service' state.sls ssh.config env=prod
chuye.backup1.service:
Data failed to compile:
----------
Requisite declaration file.sshd-files in SLS ssh.config is not formed as a single key dictionary
----------
Requisite declaration file.sshd-files in SLS ssh.config is not formed as a single key dictionary
chuye.logstash1.service:
Data failed to compile:
----------
Requisite declaration file.sshd-files in SLS ssh.config is not formed as a single key dictionary
----------
Requisite declaration file.sshd-files in SLS ssh.config is not formed as a single key dictionary
chuye.logstash2.service:
Data failed to compile:
----------
Requisite declaration file.sshd-files in SLS ssh.config is not formed as a single key dictionary
----------
Requisite declaration file.sshd-files in SLS ssh.config is not formed as a single key dictionary

解决办法:

1
2
3
4
- require:
- file.sshd-files
- watch:
- file.sshd-files

上面的值配置错误

1
2
3
4
- require:
- file: sshd-files
- watch:
- file: sshd-files

报错:在文件中调用grains报错

1
2
3
4
5
6
7
8
9
----------
ID: zabbix-agent-install
Function: file.managed
Name: /etc/zabbix_agentd.conf.bak
Result: False
Comment: Unable to manage file: Jinja variable 'item' is undefined
Started: 16:12:39.454923
Duration: 17.407 ms
Changes:

解决办法:

1
2
3
Hostname={{ grains[fqdn] }}
没有加引号
Hostname={{ grains['fqdn'] }}

报错:调用jinjia模板的时候多了一对括号

1
2
3
#!/bin/sh
-IPADDR=['10.10.86.159']
+IPADDR=chuye.logstash2.service

解决办法:

1
2
3
4
5
Solution:

Address {{ grains['fqdn_ip4'][0] }}
Result:
Address 111.111.111.111

安装方法

1
2
3
4
yum install python-pip -y
pip install docker-compose
# docker-compose -v
docker-compose version 1.8.1, build 878cff1

命令简介

Compose区分Version 1和Version 2(Compose 1.6.0+,Docker Engine 1.10.0+)。Version 2支持更多的指令。Version 1没有声明版本默认是”version 1”。Version 1将来会被弃用。
版本1指的是忽略version关键字的版本;版本2必须在行首添加version: ‘2’。

docker-compose 命令行工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# docker-compose
Define and run multi-container applications with Docker.

Usage:
docker-compose [-f <arg>...] [options] [COMMAND] [ARGS...]
docker-compose -h|--help

Options:
-f, --file FILE Specify an alternate compose file (default: docker-compose.yml)
-p, --project-name NAME Specify an alternate project name (default: directory name)
--verbose Show more output
-v, --version Print version and exit
-H, --host HOST Daemon socket to connect to

--tls Use TLS; implied by --tlsverify
--tlscacert CA_PATH Trust certs signed only by this CA
--tlscert CLIENT_CERT_PATH Path to TLS certificate file
--tlskey TLS_KEY_PATH Path to TLS key file
--tlsverify Use TLS and verify the remote
--skip-hostname-check Don't check the daemon's hostname against the name specified
in the client certificate (for example if your docker host
is an IP address)

Commands:
build Build or rebuild services
bundle Generate a Docker bundle from the Compose file
config Validate and view the compose file
create Create services
down Stop and remove containers, networks, images, and volumes
events Receive real time events from containers
exec Execute a command in a running container
help Get help on a command
kill Kill containers
logs View output from containers
pause Pause services
port Print the public port for a port binding
ps List containers
pull Pulls service images
push Push service images
restart Restart services
rm Remove stopped containers
run Run a one-off command
scale Set number of containers for a service
start Start services
stop Stop services
unpause Unpause services
up Create and start containers
version Show the Docker-Compose version information
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
### 启动容器(默认是前台启动,并打印日志)默认情况,如果该服务的容器已经存在, docker-compose up 将会停止并尝试重新创建他们(保持使用 volumes-from 挂载的卷),以保证 docker-compose.yml 的修改生效。如果你不想容器被停止并重新创建,可以使用 docker-compose up --no-recreate。如果需要的话,这样将会启动已经停止的容器。
docker-compose up
Creating kafka_zk_1
Creating kafka_kafka_1

### 如果想后台运行:
docker-compose up -d

### 查看状态:
docker-compose ps

### 停止服务:
docker-compose stop
Stopping kafka_kafka_1 ... done
Stopping kafka_zk_1 ... done

###重新启动服务:
docker-compose restart


build 构建或重新构建服务。服务一旦构建后,将会带上一个标记名,例如 web_db。可以随时在项目目录下运行 docker-compose build 来重新构建服务。

help 获得一个命令的帮助。

kill 通过发送 SIGKILL 信号来强制停止服务容器。支持通过参数来指定发送的信号,例如 $ docker-compose kill -s SIGINT

logs 查看服务的输出。

port 打印绑定的公共端口。

ps 列出所有容器。

pull 拉取服务镜像。

rm 删除停止的服务容器。

run 在一个服务上执行一个命令。

scale 设置同一个服务运行的容器个数。例如:$ docker-compose scale web=2 worker=3

docker-compose.yml 配置文件解释

每个docker-compose.yml必须定义image或者build中的一个,其它的是可选的。

image

指定镜像tag或者镜像ID。示例:

1
2
3
4
5
image: kafka
image: ubuntu:14.04
image: tutum/influxdb
image: example-registry.com:4000/postgresql
image: a4bc65fd

注意,在version 1里同时使用image和build是不允许的,version 2则可以,如果同时指定了两者,会将build出来的镜像打上名为image标签。

build

用来指定一个包含Dockerfile文件的路径。一般是当前目录.。Fig将build并生成一个随机命名的镜像。

注意,在version 1里bulid仅支持值为字符串。version 2里支持对象格式。

1
2
3
4
5
6
7
8

build: ./dir

build:
context: ./dir
dockerfile: Dockerfile-alternate
args:
buildno: 1

context \ arg

context为路径,dockerfile为需要替换默认docker-compose的文件名,args为构建(build)过程中的环境变量,用于替换Dockerfile里定义的ARG参数,容器中不可用。示例:

1
2
3
4
5
6
7
8
Dockerfile:

ARG buildno
ARG password

RUN echo "Build number: $buildno"
RUN script-requiring-password.sh "$password"

1
2
3
4
5
6
7
8
9
10
11
12
13
docker-compose.yml:

build:
context: .
args:
buildno: 1
password: secret

build:
context: .
args:
- buildno=1
- password=secret

command

用来覆盖缺省命令。示例:

1
2
3
4
command: bundle exec thin -p 3000
command也支持数组形式:

command: [bundle, exec, thin, -p, 3000]

用于链接另一容器服务,如需要使用到另一容器的mysql服务。可以给出服务名和别名;也可以仅给出服务名,这样别名将和服务名相同。同docker run –link。示例:

1
2
3
4
links:
- db
- db:mysql
- redis

使用了别名将自动会在容器的/etc/hosts文件里创建相应记录:

1
2
3
172.17.2.186  db
172.17.2.186 mysql
172.17.2.187 redis

所以我们在容器里就可以直接使用别名作为服务的主机名。

ports

用于暴露端口。同docker run -p。示例:

1
2
3
4
5
ports:
- "3000"
- "8000:8000"
- "49100:22"
- "127.0.0.1:8001:8001"

expose

expose提供container之间的端口访问,不会暴露给主机使用。同docker run –expose。

1
2
3
expose:
- "3000"
- "8000"

volumes

挂载数据卷。同docker run -v。示例:

1
2
3
4
5
volumes:
- /var/lib/mysql
- cache/:/tmp/cache
- ~/configs:/etc/configs/:ro
volumes_from

挂载数据卷容器,挂载是容器。同docker run –volumes-from。示例:

1
2
3
4
5
6
volumes_from:
- service_name
- service_name:ro
- container:container_name
- container:container_name:rw
container:container_name格式仅支持version 2。

environment

添加环境变量。同docker run -e。可以是数组或者字典格式:

1
2
3
4
5
6
7
environment:
RACK_ENV: development
SESSION_SECRET:

environment:
- RACK_ENV=development
- SESSION_SECRET

depends_on

用于指定服务依赖,一般是mysql、redis等。
指定了依赖,将会优先于服务创建并启动依赖。

links也可以指定依赖。

链接搭配docker-compose.yml文件或者Compose之外定义的服务,通常是提供共享或公共服务。格式与links相似:

1
2
3
4
external_links:
- redis_1
- project_db_1:mysql
- project_db_1:postgresql

注意,external_links链接的服务与当前服务必须是同一个网络环境。

extra_hosts

添加主机名映射。

1
2
3
extra_hosts:
- "somehost:162.242.195.82"
- "otherhost:50.31.209.229"

将会在/etc/hosts创建记录:

1
2
162.242.195.82  somehost
50.31.209.229 otherhost

extends

继承自当前yml文件或者其它文件中定义的服务,可以选择性的覆盖原有配置。

1
2
3
extends:
file: common.yml
service: webapp

service必须有,file可选。service是需要继承的服务,例如web、database。

net

设置网络模式。同docker的–net参数。

1
2
3
4
net: "bridge"
net: "none"
net: "container:[name or id]"
net: "host"

dns

自定义dns服务器。

1
2
3
4
dns: 8.8.8.8
dns:
- 8.8.8.8
- 9.9.9.9

其他参数

cpu_shares, cpu_quota, cpuset, domainname, hostname, ipc, mac_address, mem_limit, memswap_limit, privileged, read_only, restart, shm_size, stdin_open, tty, user, working_dir
这些命令都是单个值,含义请参考docker run。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cpu_shares: 73
cpu_quota: 50000
cpuset: 0,1

user: postgresql
working_dir: /code

domainname: foo.com
hostname: foo
ipc: host
mac_address: 02:42:ac:11:65:43

mem_limit: 1000000000
mem_limit: 128M
memswap_limit: 2000000000
privileged: true

restart: always

read_only: true
shm_size: 64M
stdin_open: true
tty: true

例如:

$ docker-compose run ubuntu ping docker.com
将会启动一个 ubuntu 服务,执行 ping docker.com 命令。

默认情况下,所有关联的服务将会自动被启动,除非这些服务已经在运行中。

该命令类似启动容器后运行指定的命令,相关卷、链接等等都将会按照期望创建。

两个不同点:

给定命令将会覆盖原有的自动运行命令;
不会自动创建端口,以避免冲突。
如果不希望自动启动关联的容器,可以使用 –no-deps 选项,例如

$ docker-compose run –no-deps web python manage.py shell
将不会启动 web 容器所关联的其它容器。

实战演示

1、定义Dockerfile,方便迁移到任何地方;
2、编写docker-compose.yml文件;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
zk:
image: kafka:v1
net: host
stdin_open: true
tty: true
expose:
- "2181"
command: bin/zookeeper-server-start.sh config/zookeeper.properties
kafka:
image: kafka:v1
net: host
stdin_open: true
tty: true
ports:
- "9092:9092"
command: bin/kafka-server-start.sh config/server.properties

3、运行docker-compose up启动服务

1
2
3
4
[root@linux kafka]# docker-compose up -d
Creating kafka_zk_1
Creating kafka_kafka_1

4、查看运行的服务

1
2
3
4
5
6
[root@linux kafka]# docker-compose ps
Name Command State Ports
--------------------------------------------------------------
kafka_kafka_1 bin/kafka-server-start.sh ... Up
kafka_zk_1 bin/zookeeper-server-start ... Up
[root@linux kafka]#

停止服务

1
2
docker stop kafka_kafka_1
docker stop kafka_zk_1

删除服务

1
docker-compose rm zk kafka

Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上。
Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。Docker 容器通过 Docker 镜像来 创建。容器与镜像的关系类似于面向对象编程中的对象与类。
Docker daemon 作为服务端接受来自客户的请求,并处理这些请求(创建、运行、分发容器)。 客户端和服务端既可 以运行在一个机器上,也可通过 socket 或者RESTful API 来进行通信。
Docker daemon 一般在宿主主机后台运行,等待接收来自客户端的消息。 Docker 客户端则为用户提供一系列可执行 命令,用户用这些命令实现跟 Docker daemon 交互。

docker的主要特性

  • 文件系统隔离:每个进程容器运行在完全独立的根文件系统里。
  • 资源隔离:可以使用cgroup为每个进程容器分配不同的系统资源,例如CPU和内存。
  • 网络隔离:每个进程容器运行在自己的网络命名空间里,拥有自己的虚拟接口和IP地址。
  • 写时复制:采用写时复制方式创建根文件系统,这让部署变得极其快捷,并且节省内存和硬盘空间。
  • 日志记录:Docker将会收集和记录每个进程容器的标准流(stdout/stderr/stdin),用于实时检索或批量检索。
  • 变更管理:容器文件系统的变更可以提交到新的映像中,并可重复使用以创建更多的容器。无需使用模板或手动配置。
  • 交互式Shell:Docker可以分配一个虚拟终端并关联到任何容器的标准输入上,例如运行一个一次性交互shell。

Docker 镜像

Docker 镜像是 Docker 容器运行时的只读模板,每一个镜像由一系列的层 (layers) 组成。Docker 使用 UnionFS 来将 这些层联合到单独的镜像中。UnionFS 允许独立文件系统中的文件和文件夹(称之为分支)被透明覆盖,形成一个单独连 贯的文件系统。正因为有了这些层的存在,Docker 是如此的轻量。当你改变了一个 Docker 镜像,比如升级到某个程 序到新的版本,一个新的层会被创建。因此,不用替换整个原先的镜像或者重新建立,只是一个新 的层被添加或升级 了。现在你不用重新发布整个镜像,只需要升级,层使得分发 Docker 镜像变得简单和快速。

Docker 仓库

Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。同样的,Docker 仓库也有公有和私有的概念。公有的 Docker 仓库名字是 Docker Hub。Docker Hub 提供了庞大的镜像集合供使用。这些镜像可以是自己创建,或者在别人 的镜像基础上创建。Docker 仓库是 Docker 的分发部分。

Docker 容器

Docker 容器和文件夹很类似,一个Docker容器包含了所有的某个应用运行所需要的环境。每一个 Docker 容器都是从 Docker 镜像创建的。Docker 容器可以运行、开始、停止、移动和删除。每一个 Docker 容器都是独立和安全的应用平 台,Docker 容器是 Docker 的运行部分。

docker命令行

docker 命令 英文注释 中文注释
attach Attach to a running container 当前 shell 下 attach 连接指定运行镜像
build Build an image from a Dockerfile 通过 Dockerfile 定制镜像
commit Create a new image from a container’s changes 提交当前容器为新的镜像
cp Copy files/folders between a container and the local filesystem 从容器中拷贝指定文件或者目录到宿主机
create Create a new container 创建一个新的容器,同 run,但不启动容器
diff Inspect changes on a container’s filesystem 查看 docker 容器变化
events Get real time events from the server 从 docker 服务获取容器实时事件
exec Run a command in a running container 在已存在的容器上运行命令
export Export a container’s filesystem as a tar archive 导出容器的内容流作为一个 tar 归档文件[对应import]
history Show the history of an image 展示一个镜像形成历史
images List images 列出系统当前镜像
import Import the contents from a tarball to create a filesystem image 从tar包中的内容创建一个新的文件系统映像[对应
info Display system-wide information 显示系统相关信息
inspect Return low-level information on a container, image or task 查看容器详细信息
kill Kill one or more running containers kill 指定 docker 容器
load Load an image from a tar archive or STDIN 从一个 tar 包中加载一个镜像[对应 save]
login Log in to a Docker registry. 注册或者登陆一个 docker 源服务器
logout Log out from a Docker registry. 从当前 Docker registry 退出
logs Fetch the logs of a container 输出当前容器日志信息
network Manage Docker networks 管理Docker网络
node Manage Docker Swarm nodes 管理Docker Swarm节点
pause Pause all processes within one or more containers 暂停容器
port List port mappings or a specific mapping for the container 查看映射端口对应的容器内部源端口
ps List containers 列出容器列表
pull Pull an image or a repository from a registry 从docker镜像源服务器拉取指定镜像或者库镜像
push Push an image or a repository to a registry 推送指定镜像或者库镜像至docker源服务器
rename Rename a container 重命名一个容器
restart Restart a container 重启运行的容器
rm Remove one or more containers 移除一个或者多个容器
rmi Remove one or more images 移除一个或多个镜像[无容器使用该镜像才可删除,否则需删除相关容器才可继续或 -f 强制删除]
run Run a command in a new container 创建一个新的容器并运行一个命令
save Save one or more images to a tar archive (streamed to STDOUT by default) 保存一个镜像为一个 tar 包[对应 load]
search Search the Docker Hub for images 在docker hub 中搜索镜像
service Manage Docker services 管理Docker服务
start Start one or more stopped containers 启动容器
stats Display a live stream of container(s) resource usage statistics 显示容器的实时流资源使用统计信息
stop Stop one or more running containers 停止容器
swarm Manage Docker Swarm swarm命令
tag Tag an image into a repository 给源中镜像打标签
top Display the running processes of a container 显示容器的正在运行的进程
unpause Unpause all processes within one or more containers 取消暂停容器
update Update configuration of one or more containers 更新一个或多个容器的配置
version Show the Docker version information 查看docker版本信息
volume Manage Docker volumes
wait Block until a container stops, then print its exit code 截取容器停止时的退出状态值

安装docker软件及系统环境准备

操作系统环境

1
2
3
4
5
6
[root@localhost ~15:58:47]#cat /etc/redhat-release
CentOS Linux release 7.1.1503 (Core)
[root@localhost ~11:48:09]#uname -r
3.10.0-229.el7.x86_64
[root@localhost ~11:48:24]#uname -m
x86_64

快速安装docker

1
2
3
yum install -y docker
systemctl start docker
systemctl enable docker

将docker应用程序迁移到别的位置

1
2
3
mv /var/lib/docker /data/
ln -s /data/docker/ /var/lib/docker
systemctl restart docker

docker镜像加速

1
2
3
4
5
6
cat > /etc/docker/daemon.json <<EOF
{
"registry-mirrors": ["https://docker.mirrors.ustc.edu.cn"]
}
EOF
systemctl restart docker

开源的docker镜像网站

1
2
3
https://registry.docker-cn.com
https://docker.mirrors.ustc.edu.cn
https://hub-mirror.c.163.com

docker常用命令讲解

1
2
3
4
5
6
7
8
docker search centos  ##搜索镜像
docker pull centos ##拉取官方的镜像
docker run -it --name test1 centos /bin/bash #启动容器
docker stop ”CONTAINER id“ #停止容器
docker ps -l #查看正在运行的容器
docker ps -a # 查看所有启动过的容器
docker rm "CONTAINER id" #删除容器
docker rmi "image name" #删除镜像

进入docker命令

方法一:

1
docker exec -it nginx1 bash

方法二:

1
2
3
4
5
6
7
8
cat in.sh
#!/bin/sh
CNAME=$1
CPID=$(docker inspect --format "{{.State.Pid}}" $CNAME)
nsenter --target "$CPID" --mount --uts --ipc --net --pid

执行方法:
sh in.sh names(docker容器名)

推荐使用方法二,进入docker容器

docker网络

1
2
3
4
5
docker run -P #随机映射一个端口
docker -p hostPort:dockerPort #指定端口映射
docker -p ip:hostPort:dockerPort #指定固定IP的固定端口映射
docker ip::dockerPort #指定固定ip映射端口
docker -p Port:DcoekrPort -p Port:DcoekrPort #指定多个映射端口映射

Docker 四种网络模式

docker run 创建 Docker 容器时,可以用 –net 选项指定容器的网络模式,Docker 有以下 4 种网络模式:

  • host 模式,使用 –net=host 指定。
  • container 模式,使用 –net=container:NAMEorID 指定。
  • none 模式,使用 –net=none 指定。
  • bridge 模式,使用 –net=bridge 指定,默认设置。

host 模式

如果启动容器的时候使用 host 模式,那么这个容器将不会获得一个独立的 Network Namespace,而是和宿主机共用 一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。
例如,我们在 10.10.101.105/24 的机器上用 host 模式启动一个含有 web 应用的 Docker 容器,监听 tcp 80 端口。当 我们在容器中执行任何类似 ifconfig 命令查看网络环境时,看到的都是宿主机上的信息。而外界访问容器中的应用,则 直接使用 10.10.101.105:80 即可,不用任何 NAT 转换,就如直接跑在宿主机中一样。但是,容器的其他方面,如文件 系统、进程列表等还是和宿主机隔离的。

container 模式

这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容 器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面 ,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。

none模式

这个模式和前两个不同。在这种模式下,Docker 容器拥有自己的 Network Namespace,但是,并不为 Docker容器进 行任何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、 配置 IP 等。

bridge模式

bridge 模式是 Docker 默认的网络设置,此模式会为每一个容器分配 Network Namespace、设置 IP 等,并将一个主机 上的 Docker 容器连接到一个虚拟网桥上。当 Docker server 启动时,会在主机上创建一个名为 docker0 的虚拟网桥, 此主机上启动的 Docker 容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容 器就通过交换机连在了一个二层网络中。接下来就要为容器分配 IP 了,Docker 会从 RFC1918 所定义的私有 IP 网段 中,选择一个和宿主机不同的IP地址和子网分配给 docker0,连接到 docker0 的容器就从这个子网中选择一个未占用的 IP 使用。如一般 Docker 会使用 172.17.0.0/16 这个网段,并将 172.17.42.1/16 分配给 docker0 网桥(在主机上使用 ifconfig 命令是可以看到 docker0 的,可以认为它是网桥的管理接口,在宿主机上作为一块虚拟网卡使用)

docker映射文件系统

1
2
3
4
docker run -v /data  #挂载容器的/data目录
docker run -v src:dst ##挂载容器的目录到真实目录中

docker --volumes-from #挂载容器到容器目录中。

注意:如果直接挂载一个文件,很多文件编辑工具,包括 vi 或者 sed --in-place,可能会造成文件 inode 的改变,从 Docker 1.1 .0起,这会导致报错误信息。所以最简单的办法就直接挂载文件的父目录。

docker拷贝文件

1
docker cp 446cd224ed6f:/etc/hosts /etc/backup  ##从docker中拷贝文件到实体服务器

基于文件系统拷贝文件

还有一个方法,算是比较麻烦的。
新版本的docker中这种方式以及废弃了。

1
2
3
4
5
6
7
8
9
10
11
#### 获取容器Id
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4e52a6a5db69 kafka:v1 "bin/zookeeper-server" 2 hours ago Up About an hour kafka_zk_1
446cd224ed6f kafka:v1 "bin/kafka-server-sta" 2 hours ago Exited (1) About an hour ago kafka_kafka_1
#### 获取完整得ID值
[root@linux src]# docker inspect -f '{{.ID}}' 446cd224ed6f
446cd224ed6f5d6fd14a65f80264156c074bd2cf9af34910d7123b7dda1d3926

#### 拷贝文件到容器中
cp /data/scripts/docker_in.sh /var/lib/docker/devicemapper/mnt/446cd224ed6f5d6fd14a65f80264156c074bd2cf9af34910d7123b7dda1d3926/rootfs/root

编写docker file

1
2
3
4
5
6
7
8
9
10
FROM #指定基础镜像
MAINTAINER #镜像的作者
RUN #在shell或者exec的环境中执行的命令。
ADD #docker镜像中添加文件。
WORKDIR #指定RUN,CMD,ENTERPOINT命令的工作目录。
VOLUME #授权访问物理机的目录
EXPOSE#指定容器运行时的监听端口。
CMD #提供容器默认的执行命令。
ENV #设置环境变量。
USER # 给镜像设置一个UID。

一个dockerfile中只能有一个CMD,如果有多个只有最后一个会执行。

推荐使用数组写 CMD 的命令,如果不是数组,则运行时,会加上 /bin/sh -c.

dockerfile最佳实践

  • 所有的dockerfile 都必须FROM命令开始。
  • 避免dockerfile映射公网的端口。
  • 将经常改动的地方放在dockerfile的下面。

dockerfile实例

1: 创建一个目录来存放dockerfile需要的文件:

1
mkdir /data/dockerfile/nginx -p

2: 编写dockerfile文件。

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
cd /data/dockerfile/nginx/
vim Dockerfile ##首字母必须大小
# this is my first Dockerfile
#Version 1.0
#Author: niuhengbo


#Base images
From centos
#MAINTAINER
MAINTAINER biglittleant


#ADD
ADD nginx-1.10.1.tar.gz /usr/local/src

#RUN
RUN yum install -y wget gcc gcc-c++ make openssl-devel pcre pcre-devel
RUN useradd -s /sbin/nologin -M www

#WORKDIR
WORKDIR /usr/local/src/nginx-1.10.1
RUN ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-http_stub_status_module &&make && make install
RUN echo "daemon off;" >> /usr/local/nginx/conf/nginx.conf

ENV PATH /usr/local/nginx/sbin:$PAHT
EXPOSE 80
CMD ["nginx"]

3: 上传dockerfile需要的软件到目录中.

1
2
3
4
[root@linux-node1 nginx10:58:08]#ll
total 892
-rw-r--r-- 1 root root 598 Jun 16 10:34 Dockerfile
-rw-r--r-- 1 root root 909077 Jun 15 17:18 nginx-1.10.1.tar.gz

4: 生成docker镜像.

1
2
3
4
5
docker build -t nginx-file:v1 /data/dockerfile/nginx/
docker images
[root@linux-node1 nginx10:38:45]#docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
nginx-file v1 a775b585a5f3 6 minutes ago 381 MB

CMD 和 ENTRYPOINT 的区别

  1. 多行CMD命令,最终只有最后一行CMD命令,才能执行。
  2. docker run 的时候,如果手动输入了执行命令,则会覆盖dockerfile中的默认CMD命令。
  3. ENTRYPOINT 命令 在docker run的时候不会被覆盖。

推荐用法
ENTRYPOINT [“/usr/sbin/nginx”]
CMD [“-h”]

可以在启动的时候,指定参数,来启动容器,如果不想指定参数,则会使用默认的CMD。
可以使用–entrypoint 来覆盖ENTRYPOINT的指令。

其他的docker命令

1
2
3
4
5
6
7
## 配置容器主机名
docker run -h HOSTNAME or --hostname=HOSTNAME
#导出镜像
docker save centos > centos-16-02-17.tar
#存入镜像
docker load --input ubuntu_14.04.tar
docker load < ubuntu_14.04.tar

常用docker命令

关闭所有正在运行容器

1
docker ps | awk  '{print $1}' | xargs docker stop

删除所有容器应用

1
docker ps -a | awk  '{print $1}' | xargs docker rm

或者

1
docker rm $(docker ps -a -q)

查看容器内的logs

1
2
3
4
docker logs 63ba23b2bf66
192.168.56.1 - - [03/Aug/2017:08:39:23 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "-"
192.168.56.1 - - [03/Aug/2017:08:39:24 +0000] "GET /favicon.ico HTTP/1.1" 404 571 "http://192.168.56.12:8082/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "-"
2017/08/03 08:39:24 [error] 5#5: *1 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 192.168.56.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "192.168.56.12:8082", referrer: "http://192.168.56.12:8082/"
1
2
docker logs -f 63ba23b2bf66
192.168.56.1 - - [03/Aug/2017:08:40:11 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" "-"

查看各个容器的资源使用情况

1
2
3
4
5
docker stats
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
63ba23b2bf66 0.00% 7.402 MiB / 979.6 MiB 0.76% 4.126 kB / 3.428 kB 6.725 MB / 0 B 0
a5736e32b8d5 0.00% 13.67 MiB / 979.6 MiB 1.40% 16.27 kB / 14.6 kB 15.04 MB / 0 B 0
a81f2cfd558a 0.57% 35.79 MiB / 979.6 MiB 3.65% 208.2 kB / 547.6 kB 49.06 MB / 792.1 kB 0

查看容器的详细信息

1
docker inspect 63ba23b2bf66

查看容器内的进程情况

1
2
3
4
docker top 63ba23b2bf66
UID PID PPID C STIME TTY TIME CMD
root 39655 39641 0 16:35 ? 00:00:00 nginx: master process nginx -g daemon off;
101 39673 39655 0 16:35 ? 00:00:00 nginx: worker process

上传镜像

1
2
3
4
docker login harbor.biglittleant.cn ## 登录镜像仓库
docker commit -m 'my nginx' sdfkjsldfk niuhengbo/mynginx:v1 ##将允许的docker容器提交到image中。
docker tag niuhengbo/mynginx:v1 192.168.56.11:5000/niuhengbo/mynginx:latest ##给images 打tags
docker push harbor.biglittleant.cn/niuhengbo/mynginx:latest # 推到远端的镜像仓库

查看docker的详细信息

1
2
找到容器id
docker inspect f33b254ccd02 | less

docker 生产环境目录架构

docker 分层设计架构

  • 系统层–》运行环境层–》应用服务层
  • system 存放各种优化后的系统。
  • runtime 存放各种基础环境,比如:java环境,php环境,python环境等。
  • app 存放各种完整业务。比如api业务,admin业务。
1
2
3
4
5
6
7
8
9
10
11
12
13
├── app
│   ├── shop-api
│   ├── xxx-admin
│   └── xxx-api
├── runtime
│   ├── java
│   ├── php
│   ├── python
│   └── python-ssh
└── system
├── centos
├── centos-ssh
└── ubuntu

参考文档

Docker - 从入门到实践
docker的图像管理界面
docker-daemon

报错汇总

在虚拟机中运行docker是有个警告

1
Usage of loopback devices is strongly discouraged for production use. Either use `--storage-opt dm.thinpooldev` or use `--storage-opt dm.no_warn_on_loop_devices=true` to suppress this warning.

解决办法:

1
2
[root@localhost ~]# vim /etc/sysconfig/docker-storage
DOCKER_STORAGE_OPTIONS="--storage-opt dm.no_warn_on_loop_devices=true"

–privileged 启动特权模式 允许我们以其宿主机具有的所有能力运行容器,包括一些内核特性和设备访问。

1
kernel:unregister_netdevice: waiting for lo to become free. Usage count = 1

内核bug 参考 https://github.com/moby/moby/issues/5618
至今未解决。

报错一 python3.5 使用压缩的时候提示没有zlib模块。

1
2
3
4
5
6
7
  File "1.py", line 6, in <module>
tar = tarfile.open("sample.tar.gz", "w:gz")
File "/usr/local/python3/lib/python3.5/tarfile.py", line 1580, in open
return func(name, filemode, fileobj, **kwargs)
File "/usr/local/python3/lib/python3.5/tarfile.py", line 1624, in gzopen
raise CompressionError("gzip module is not available")
tarfile.CompressionError: gzip module is not available

解决办法

先按照zlib模块,在编译安装

1
2
3
4
5
yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel -y

./configure --prefix=/data/app/python-3.5.2 --enable-shared
make
make install

执行命令继续报错

1
python3: error while loading shared libraries: libpython3.5m.so.1.0: cannot open shared object file: No such file or directory

解决办法

1
2
echo /data/app/python3/lib/ >> /etc/ld.so.conf.d/local.conf
ldconfig

go语言安装过程

1
2
3
4
5
[root@linux-node1 ~]# yum install -y gcc glibc gcc-c++ make git
[root@linux-node1 ~]# cd /usr/local/src
[root@linux-node1 ~]# wget https://storage.googleapis.com/golang/go1.6.1.linux-amd64.tar.gz
[root@linux-node1 ~]# tar zxf go1.6.1.linux-amd64.tar.gz
[root@ linux-node1 src]# mv go /usr/local/

配置环境变量

1
2
3
4
5
6
[root@ linux-node1 ~]# mkdir /usr/local/go/work/
[root@ linux-node1 ~]# vim ~/.bash_profile
export GOROOT=/usr/local/go
export GOPATH=/usr/local/go/work
PATH=$PATH:$HOME/bin:$GOROOT/bin:$GOPATH/bin
[root@linux-node1 ~]# source .bash_profile

检查安装是否正常

1
2
[root@linux-node1 ~]#go version
go version go1.6.1 linux/amd64

VSFTP简介

FTP是仅基于TCP的服务,不支持UDP。与众不同的是FTP使用2个端口,一个数据端口和一个命令端口(也可叫做控制端口)。通常来说这两个端口是21(命令端口)和20(数据端口)。但FTP工作方式的不同,数据端口并不总是20。这就是主动与被动FTP的最大不同之处。

 

vsftpd提供了3种ftp登录形式:

anonymous(匿名帐号)

使用anonymous是应用广泛的一种FTP服务器.如果用户在FTP服务器上没有帐号,那么用户可以以anonymous为用户名,以自己的电子邮件地址为密码进行登录.当匿名用户登录FTP服务器后,其登录目录为匿名FTP服务器的根目录/var/ftp.为了减轻FTP服务器的负载,一般情况下,应关闭匿名帐号的上传功能.

real(真实帐号)

real也称为本地帐号,就是以真实的用户名和密码进行登录,但前提条件是用户在FTP服务器上拥有自己的帐号.用真实帐号登录后,其登录的目录为用户自己的目录,该目录在系统建立帐号时系统就自动创建.

guest(虚拟帐号)

如果用户在FTP服务器上拥有帐号,但此帐号只能用于文件传输服务,那么该帐号就是guest,guest是真实帐号的一种形式,它们的不同之处在于,geust登录FTP服务器后,不能访问除宿主目录以外的内容.

安装vsftpd

1
2
3
4
5
yum install vsftpd
## 启动ftp
systemctl start vsftpd
## 或者
/etc/init.d/vsftpd start

查看服务器端口是否存在

1
ss -lntup |grep 22

配置文件解释

生产配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
egrep -v "#|^$" /etc/vsftpd/vsftpd.conf
anonymous_enable=no ##禁止匿名账号登录
local_enable=YES
write_enable=YES
local_umask=022
dirmessage_enable=YES
xferlog_enable=YES
connect_from_port_20=YES
xferlog_file=/var/log/xferlog
xferlog_std_format=YES
chroot_local_user=YES
listen=NO
listen_ipv6=YES
pam_service_name=vsftpd
userlist_enable=YES
tcp_wrappers=YES

默认配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#使用户不能离开主目录
chroot_list_enable=YES

#设定不允许匿名访问
anonymous_enable=NO
#设定本地用户可以访问。注:如使用虚拟宿主用户,在该项目设定为NO的情况下所有虚拟用户将无法访问
local_enable=YES

write_enable=YES
local_umask=022
dirmessage_enable=YES
xferlog_enable=YES
connect_from_port_20=YES
xferlog_std_format=YES
#服务器独立运行
listen=YES

pam_service_name=vsftpd
userlist_enable=YES
tcp_wrappers=YES

配置日志和上传下载

1
2
3
4
5
6
7
8
9
10
#设定支持ASCII模式的上传和下载功能
ascii_upload_enable=YES
ascii_download_enable=YES

#配置vsftpd日志(可选)
xferlog_enable=YES
xferlog_std_format=YES
xferlog_file=/var/log/xfer.log
dual_log_enable=YES
vsftpd_log_file=/var/log/vsftpd.log

如果启用vsftpd日志需手动建立日志文件

1
2
touch /var/log/xfer.log
touch /var/log/vsftpd.log

配置到这里,一个普通的ftp就可以交付使用。
使用系统账号可以登录自己的ftp。

配置匿名用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 设定允许匿名访问
anonymous_enable=YES

# 增加匿名访问目录
anon_root=/var/ftp/pub

# 打开匿名用户上传/删除/重命名权限
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES

# 匿名用户的掩码
anon_umask=022

# 匿名登录时,不检验密码
no_anon_password=YES

# 匿名用户10分钟无操作则掉线
idle_session_timeout=600

默认情况下匿名用户没有创建目录的权限,增加匿名用户的权限

1
chown -R ftp.ftp pub/

配置虚拟用户登录

所谓虚拟用户就是没有使用真实的帐户,只是通过映射到真实帐户和设置权限的目的。虚拟用户不能登录CentOS系统。

创建虚拟用户6步走:

  1. 在vsftpd.cong文件中添加支持配置

  2. 建立虚拟FTP用户的账号数据库文件

  3. 创建FTP根目录及虚拟用户映射的系统用户

  4. 建立支持虚拟用户的PAM认证文件

  5. 在个别虚拟用户建立独立的配置文件以实现权限访问

  6. 重启vsftpd服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
vi /etc/vsftpd/vsftpd.conf
#PAM认证文件名。PAM将根据/etc/pam.d/vsftpd进行认证
pam_service_name=vsftpd
#设定启用虚拟用户功能
guest_enable=YES
#指定虚拟用户的宿主用户,CentOS中已经有内置的ftp用户了
guest_username=ftp
#设定虚拟用户个人vsftp的CentOS FTP服务文件存放路径。存放虚拟用户个性的CentOS FTP服务文件(配置文件名=虚拟用户名)
user_config_dir=/etc/vsftpd/vuser_conf
#配置vsftpd日志(可选)
xferlog_enable=YES
xferlog_std_format=YES
xferlog_file=/var/log/xferlog
dual_log_enable=YES
vsftpd_log_file=/var/log/vsftpd.log

进行认证

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
#安装Berkeley DB工具

yum install db4 db4-utils -y

#创建用户密码本,注意奇行是用户名,偶行是密码
cat >>/etc/vsftpd/vuser_passwd.txt<<EOF
test
123456
EOF

#生成虚拟用户认证的db文件
db_load -T -t hash -f /etc/vsftpd/vuser_passwd.txt /etc/vsftpd/vuser_passwd.db


# 指定认证文件名称,全部注释掉原来语句,再增加以下两句
vi /etc/pam.d/vsftpd

auth required pam_userdb.so db=/etc/vsftpd/vuser_passwd
account required pam_userdb.so db=/etc/vsftpd/vuser_passwd

#创建虚拟用户配置文件,为虚拟用户配置独立的权限
mkdir /etc/vsftpd/vuser_conf/
#文件名等于vuser_passwd.txt里面的账户名,否则下面设置无效
vi /etc/vsftpd/vuser_conf/test

#虚拟用户根目录,根据实际情况修改
local_root=/data/ftp
write_enable=YES
anon_umask=022
anon_world_readable_only=NO
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES

虚拟用户根目录必须具有FTP账号的权限。
为了使服务器能够使用上述生成的数据库文件,对客户端进行身份验证,需要调用系统的PAM模块。
PAM(Plugable Authentication Module)为可插拔认证模块,不必重新安装应用系统,通过修改指定的配置文件,调整对该程序的认证方式。
PAM模块配置文件路径为/etc/pam.d/目录,此目录下保存着大量与认证有关的配置文件,并以服务名称命名。

配置PASV(被动模式)

vsftpd默认没有开启PASV模式,FTP只能通过PORT模式连接。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#开启PASV模式
pasv_enable=YES
#最小端口号
pasv_min_port=40000
#最大端口号
pasv_max_port=40080
pasv_promiscuous=YES

#在防火墙配置内开启40000到40080端口(如果没有防火墙可以忽略)
-A INPUT -m state --state NEW -m tcp -p -dport 40000:40080 -j ACCEPT

#重启iptabls和vsftpd
service iptables restart
service vsftpd restart

现在可以使用PASV模式连接你的FTP服务器了~

设置FTP根目录权限

1
2
3
4
5
6
7
#最新的vsftpd要求对主目录不能有写的权限所以ftp为755,主目录下面的子目录再设置777权限
mkdir /data/ftp
chmod -R 755 /data
chmod -R 777 /data/ftp

#建立限制用户访问目录的空文件
touch /etc/vsftpd/chroot_list

vsftpd的高级玩法

配置SSL连接

我们登录ftp时的密码都是明文登录的,这样极不安全,所以我们可以使用基于ssl的ftp登录传输方式。
首先我们要为ftp签署证书;再在配置文件中添加下列内容

1
2
3
4
5
6
7
8
9
ssl_enable=YES     启用ssl
ssl_tlsv1=YES 启用tls v1版本
ssl_sslv2=YES 启用ssl v2版本
ssl_sslv3=YES
allow_anon_data_ssl=NO 匿名用户一般不需要
force_local_data_ssl=YES本地用户传输时是否使用ssl
force_local_logins_ssl=YES本地用户登录时是否使用ssl
rsa_cert_file=/etc/vsftpd/ssl/vsftpd.crt 证书路径
rsa_private_key_file=/etc/vsftpd/ssl/vsftpd.key私钥路径

注意事项

常见问题

默认情况下,ftp的根目录为/var/ftp,为了安全,这个目录默认不允许设置为777权限,否则ftp将无法访问。但是我们要匿名上传文件,需要“other”用户的写权限,正确的做法:
在/var/ftp中建立一个pub(名子自己起吧)文件夹,将个文件夹权限设置为777(视具体需要自己设),在upload这个文件夹中,匿名用户可以上传文件、创建文件夹、删除文件等。一般至此,便实现vsftpd匿名用户的上传下载了。如果还不行可能selinux的问题,关闭即可。

知识补充

主动连接和被动连接的区别

PORT(主动模式)

PORT中文称为主动模式,工作的原理: FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,客户端随机开放一个端口(1024以上),发送 PORT命令到FTP服务器,告诉服务器客户端采用主动模式并开放端口;FTP服务器收到PORT主动模式命令和端口号后,通过服务器的20端口和客户端开放的端口连接,发送数据。

PASV(被动模式)

PASV是Passive的缩写,中文成为被动模式,工作原理:FTP客户端连接到FTP服务器的21端口,发送用户名和密码登录,登录成功后要list列表或者读取数据时,发送PASV命令到FTP服务器, 服务器在本地随机开放一个端口(1024以上),然后把开放的端口告诉客户端, 客户端再连接到服务器开放的端口进行数据传输。

两种模式的对比

  • 主动模式,服务器端使用20端口连接客户端的随机端口发送数据。
  • 被动模式:服务器端开发随机端口供客户端连接。
  • 主动模式:需要客户端必须开放端口给服务器,很多客户端都是在防火墙内,开放端口给FTP服务器访问比较困难。
  • 被动模式:只需要服务器端开放端口给客户端连接就行了。

我在实际项目中碰到的问题是,FTP的客户端和服务器分别在不同网络,两个网络之间有至少4层的防火墙,服务器端只开放了21端口, 客户端机器没开放任何端口。FTP客户端连接采用的被动模式,结果客户端能登录成功,但是无法LIST列表和读取数据。很明显,是因为服务器端没开放被动模式下的随机端口导致。

遇到的问题

由于被动模式下,服务器端开放的端口随机,但是防火墙要不能全部开放,解决的方案是,在ftp服务器配置被动模式下开放随机端口在 50000-60000之间(范围在ftp服务器软件设置,可以设置任意1024上的端口段),然后在防火墙设置规则,开放服务器端50000-60000之间的端口端。

主动模式下,客户端的FTP软件设置主动模式开放的端口段,在客户端的防火墙开放对应的端口段。

帮助文档

常见错误

报错一:
点击详细错误的时候是下面的提示
vsftpd: refusing to run with writable root inside chroot() 错误的解决办法
一下是解决办法:
为了避免一个安全漏洞,从 vsftpd 2.3.5 开始,chroot 目录必须不可写。使用命令:

1
2
# chmod a-w /home/user
user 为FTP所连接的目录

报错二:
500 OOPS: bad bool value in config file for: tcp_wrappers

tcp_wrappers 多了一个空格,删除空格问题解决。

salt环境介绍

本文的在master中配置的file_roots如下:

1
2
3
4
5
6
7
file_roots:
base:
- /srv/salt/base
prod:
- /srv/salt/prod
test:
- /srv/salt/test

salt目录配置

1
2
3
4
5
6
7
8
9
[root@localhost java]# pwd
/srv/salt/prod/java
[root@localhost prod]# tree java/
java/
├── files
│   └── jdk-8u65-linux-x64.tar.gz
└── java-install.sls

1 directory, 2 files

salt文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@localhost java]# cat java-install.sls
java_install:
file.managed:
- name: /usr/local/src/jdk-8u65-linux-x64.tar.gz
- source: salt://java/files/jdk-8u65-linux-x64.tar.gz
- user: root
- group: root
- mode: 755
cmd.run:
- name: mkdir -p /data/app/ && cd /usr/local/src/ && tar -zxf jdk-8u65-linux-x64.tar.gz && mv jdk1.8.0_65/ /data/app/ && ln -s /data/app/jdk1.8.0_65/ /data/app/java
- unless: test -d /data/app/jdk1.8.0_65/
- require:
- file: java_install

java_init:
file.append:
- name: /etc/profile
- text:
- '###setup java by niu at 2015-12-10'
- export JAVA_HOME=/data/app/java
- export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH

注意文件的缩进和空格。
jinja模板对空格有强依赖。

在所有minion端安装java程序。

1
salt '*' state.sls java.java-install env=prod

登录minion端 查看结果。

1
2
3
4
> java -version
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)

注意

  1. salt文件的书写要注意空格的缩进。
  2. 以上内容只在centos6,7系统下测试过。

Java是由Sun Microsystems公司于1995年5月推出的Java面向对象程序设计语言和Java平台的总称。由James Gosling和同事们共同研发,并在1995年正式推出。

Java分为三个体系:

  • JavaSE(J2SE)(Java2 Platform Standard Edition,java平台标准版)
  • JavaEE(J2EE)(Java 2 Platform,Enterprise Edition,java平台企业版)
  • JavaME(J2ME)(Java 2 Platform Micro Edition,java平台微型版)。

系统版本

1
2
3
4
5
6
cat /etc/redhat-release
# CentOS Linux release 7.1.1503 (Core)
uname -r
# 3.10.0-229.el7.x86_64
uname -m
# x86_64

安装过程

上传java到/usr/local/src/目录下。

1
2
3
4
cd /usr/local/src/
tar -zxf jdk-8u65-linux-x64.tar.gz
mv jdk1.8.0_65/ /data/app/
ln -s /data/app/jdk1.8.0_65/ /data/app/java
为java配置环境变量
1
2
3
4
5
vim /etc/profile
export JAVA_HOME=/data/app/java
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
export JRE_HOME=/data/app/java/jre
export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar
使profile文件中配置的环境变量生效
1
source /etc/profile
验证JAVA是否安装成功
1
2
3
4
> java -version
java version "1.8.0_65"
Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)
0%