Total Pageviews

Sunday 5 May 2024

CSS 的预处理器 Sass

 认识到 Sass(从 Sass 3 开始的新语法规则被称为 SCSS,即 Sassy CSS) 这个 CSS 的处理器,同时 Compass 又是一个高效的开发 Sass 的利器。

闲话少说,RubyGems 下的安装

$ gem install sass
$ gem install compass

创建一个新项目

$ cd /your/jekyll/path
$ compass create .

其中 config.rb 文件可以对之进行一些修改,譬如输出格式

:nested		# 默认值,嵌套缩进
:expanded	# 无缩进、扩展
:compact	# 简洁格式
:compressed	# 压缩后

以下是我的配置

# Require any additional compass plugins here.

# Set this to the root of your project when deployed:
http_path = "/"
css_dir = "style/css"
sass_dir = "style/_sass"
images_dir = "style/images"
javascripts_dir = "style/js"

# You can select your preferred output style here (can be overridden via the command line):
# output_style = :expanded or :nested or :compact or :compressed
output_style = :compressed

当然也可以不运行 compass create . 来创建目录,只需 touch config.rb,且填充以上内容即可

实时监控 Sass 目录,使之修改保存后,即可编译成对应目录的 CSS

$ compass watch .

由于此过程会生成 .sass-cache目录,提交到代码库时,将 .sass-cache 写入 .gitignore

$ cat .gitignore
_site/*
_theme_packages/*

Thumbs.db
.DS_Store

!.gitkeep

.rbenv-version
.rvmrc
.sass-cache

不过,Jekyll 2.4.0 开始内置 Sass 预处理器,可以直接生成页面需要的样式。GitHub Pages 服务已经支持 Jekyll 2.4.0 版本。

以下是我的目录结构

assets
├── _sass
│   ├── _bootstrap.scss
│   ├── _custom.scss
│   ├── _font-awesome.scss
│   ├── _havee.scss
│   ├── _pygments.scss
│   ├── bootstrap
│   │   ├── _alerts.scss
│   │   ├── _badges.scss
│   │   ├── _breadcrumbs.scss
│   │   ├── _button-groups.scss
│   │   ├── _buttons.scss
│   │   ├── _carousel.scss
│   │   ├── _close.scss
│   │   ├── _code.scss
│   │   ├── _component-animations.scss
│   │   ├── _dropdowns.scss
│   │   ├── _forms.scss
│   │   ├── _glyphicons.scss
│   │   ├── _grid.scss
│   │   ├── _input-groups.scss
│   │   ├── _jumbotron.scss
│   │   ├── _labels.scss
│   │   ├── _list-group.scss
│   │   ├── _media.scss
│   │   ├── _mixins.scss
│   │   ├── _modals.scss
│   │   ├── _navbar.scss
│   │   ├── _navs.scss
│   │   ├── _normalize.scss
│   │   ├── _pager.scss
│   │   ├── _pagination.scss
│   │   ├── _panels.scss
│   │   ├── _popovers.scss
│   │   ├── _print.scss
│   │   ├── _progress-bars.scss
│   │   ├── _responsive-embed.scss
│   │   ├── _responsive-utilities.scss
│   │   ├── _scaffolding.scss
│   │   ├── _tables.scss
│   │   ├── _theme.scss
│   │   ├── _thumbnails.scss
│   │   ├── _tooltip.scss
│   │   ├── _type.scss
│   │   ├── _utilities.scss
│   │   ├── _variables.scss
│   │   ├── _wells.scss
│   │   └── mixins
│   │       ├── _alerts.scss
│   │       ├── _background-variant.scss
│   │       ├── _border-radius.scss
│   │       ├── _buttons.scss
│   │       ├── _center-block.scss
│   │       ├── _clearfix.scss
│   │       ├── _forms.scss
│   │       ├── _gradients.scss
│   │       ├── _grid-framework.scss
│   │       ├── _grid.scss
│   │       ├── _hide-text.scss
│   │       ├── _image.scss
│   │       ├── _labels.scss
│   │       ├── _list-group.scss
│   │       ├── _nav-divider.scss
│   │       ├── _nav-vertical-align.scss
│   │       ├── _opacity.scss
│   │       ├── _pagination.scss
│   │       ├── _panels.scss
│   │       ├── _progress-bar.scss
│   │       ├── _reset-filter.scss
│   │       ├── _resize.scss
│   │       ├── _responsive-visibility.scss
│   │       ├── _size.scss
│   │       ├── _tab-focus.scss
│   │       ├── _table-row.scss
│   │       ├── _text-emphasis.scss
│   │       ├── _text-overflow.scss
│   │       └── _vendor-prefixes.scss
│   └── font-awesome
│       ├── _bordered-pulled.scss
│       ├── _core.scss
│       ├── _fixed-width.scss
│       ├── _icons.scss
│       ├── _larger.scss
│       ├── _list.scss
│       ├── _mixins.scss
│       ├── _path.scss
│       ├── _rotated-flipped.scss
│       ├── _spinning.scss
│       ├── _stacked.scss
│       └── _variables.scss
├── css
│   └── style.scss
├── fonts
│   ├── FontAwesome.otf
│   ├── fontawesome-webfont.eot
│   ├── fontawesome-webfont.svg
│   ├── fontawesome-webfont.ttf
│   ├── fontawesome-webfont.woff
│   ├── glyphicons-halflings-regular.eot
│   ├── glyphicons-halflings-regular.svg
│   ├── glyphicons-halflings-regular.ttf
│   └── glyphicons-halflings-regular.woff
├── img
│   ├── loading.gif
│   └── url.png
└── js
    ├── bootstrap.min.js
    ├── jquery.min.js
    └── webcore.js

 

CentOS 7的配置记录

首先当然是更新到最新的包

# yum update

hostname

# hostname yourdomain
# hostnamectl set-hostname yourdomain

Timezone

# timedatectl set-timezone Asia/Shanghai

查看时区

# timedatectl

adduser

不喜 root ssh,于是添加一个用户,因为用得到 sudo,故添加到 wheel 组

# useradd -m -G users,wheel test
# passwd test

firewall

# systemctl start firewalld
# systemctl enable firewalld

这里只添加基本的对外服务:

# firewall-cmd --permanent --zone=public --add-service=http
# firewall-cmd --permanent --zone=public --add-service=https
# firewall-cmd --reload

确认下

# firewall-cmd --permanent --zone=public --list-services

iptables

或者,你可能仍然习惯使用 iptables,则

# yum install iptables-services iptables

规则文件 /etc/sysconfig/iptables,写入内容

*filter
:INPUT DROP [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -p icmp -m icmp --icmp-type echo-request -j ACCEPT
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 28480 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 2377 -j ACCEPT
-A INPUT -p udp -m state --state NEW -m udp --dport 4789 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 7946 -j ACCEPT
-A INPUT -p udp -m state --state NEW -m udp --dport 7946 -j ACCEPT
-A INPUT -p esp -j ACCEPT
-A INPUT -m conntrack --ctstate INVALID -j DROP
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A FORWARD -m conntrack --ctstate INVALID -j DROP
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT

随后导入规则,再启用服务

# iptables-restore < /etc/sysconfig/iptables
# systemctl enable iptables && systemctl start iptables

ssh

调整 sshd 服务,采用 key 登陆,编辑 /etc/ssh/sshd_config

......
AcceptEnv LANG LC_*

Subsystem	sftp	/usr/lib/openssh/sftp-server

Protocol 2
UsePAM yes
UseDNS no
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
AddressFamily inet
PermitRootLogin no
PasswordAuthentication no
SyslogFacility AUTHPRIV
PubkeyAuthentication yes
ChallengeResponseAuthentication no
ClientAliveInterval 60
Port port-num
Match User user-name
    X11Forwarding no
    PermitTTY yes

/home/test

# mkdir .ssh
# chown test:test -R .ssh
# chmod 700 .ssh

上传你的 pub key/home/test/.ssh 目录,改名为 authorized_keys 并修改权限

# chown test:test /home/test/authorized_keys
# chmod 600 /home/test/authorized_keys

因为更改了默认的 22 端口,安装一个 selinux 工具

# yum install policycoreutils-python
# semanage port -a -t ssh_port_t -p tcp yourport
# firewall-cmd --zone=public --permanent --add-port=yourport/tcp
# firewall-cmd --zone=public --permanent --remove-service=ssh
# firewall-cmd --reload

然后重启下 sshd 服务

# systemctl restart sshd

确认下 sshd 服务

# ss -alnptu | grep sshd

tmpfs

内存足够的话,直接将 tmpfs 挂载至 /tmp,先检查下

# systemctl is-enabled tmp.mount

如果没有,需要手动操作下

# systemctl enable tmp.mount && systemctl start tmp.mount

个别主机上采用的模版镜像,可能默认 mask 了服务,你可能需要先 unmask

# systemctl unmask tmp.mount && systemctl enable tmp.mount && systemctl start tmp.mount

当然,我们也可以使用传统的方式来挂载,譬如在 /etc/fstab 中指定

tmpfs   /tmpfs  tmpfs   size=512m   0 0

如果想要调整当前 tmpfs 的大小,可以如此操作

# mount -o remount,size=N /tmp

swap

小内存,是需要 swap 的,而我习惯不论 8G 以内的内存,创建 swapfile

# fallocate -l 64M /swap
or
# dd if=/dev/zero of=/swap bs=1 coun=0 seek=64M         # seek 方式来创建稀疏文件
# chmod 600 /swap
# mkswap /swap
# swapon /swap

临时卸载 swap

# swapoff /swap
or
# swapoff -a

最后,写入 fstab

/swap	none	swap	sw	0 0

性能优化方面,其实我们还是希望系统尽量使用物理内存,而不要有限使用 swap 交换文件,swappiness 参数代表内核对于交换空间的喜好,值越小代表越减少内存的交换,从而提升一些响应速度。编辑 /etc/sysctl.conf

vm.swappiness=1
vm.vfs_cache_pressure=50

zram

swap 频繁交换会极大的影响主机性能,现在一般对小内存主机,使用 zram,不过 CentOS 7 并没有提供管理脚本,自己创建一个

# touch /etc/init.d/zramswap
# chmod +x /etc/init.d/zramswap

写入如下内容

#!/bin/bash

NUM_CPUS=$(nproc)
[ "$NUM_CPUS" != 0 ] || NUM_CPUS=1
NUM_DEVS=$NUM_CPUS
FACTOR=50 # percentage
TOTALRAM=$(grep MemTotal /proc/meminfo | awk ' { print $2 } ')
DISK_SIZE=$(($TOTALRAM/$NUM_CPUS*$FACTOR/100*1024))

# show supported compression algorithms: `cat /sys/block/zram*/comp_algorithm`
# select your compression algorithm, lzo is the default
# speed: lz4 > zstd > lzo
# compression: zstd > lzo > lz4
COMP_ALGORITHMS=lzo

#Defaults for vm.overcommit_memory, vm.page-cluster, vm.swappiness
OVERCOMMIT_MEMORY=0
PAGE_CLUSTER=3
SWAPPINESS=100


start() {
  [ ! -e /sys/module/zram ] && modprobe zram num_devices=$NUM_DEVS || modprobe -r zram && modprobe zram num_devices=$NUM_DEVS
  for i in /sys/block/zram*; do
    /usr/bin/echo $COMP_ALGORITHMS > ${i}/comp_algorithm;
    /usr/bin/echo $DISK_SIZE > ${i}/disksize;
  done

  for i in /dev/zram*; do
    /usr/sbin/mkswap ${i};
    /usr/sbin/swapon -d -p100 ${i};
  done

  echo 1 > /proc/sys/vm/overcommit_memory
  echo 0 > /proc/sys/vm/page-cluster
  echo 100 > /proc/sys/vm/swappiness
}

stop() {
  [ ! -e /sys/module/zram ] && exit 0

  echo $OVERCOMMIT_MEMORY > /proc/sys/vm/overcommit_memory
  echo $PAGE_CLUSTER > /proc/sys/vm/page-cluster
  echo $SWAPPINESS > /proc/sys/vm/swappiness

  for i in /dev/zram*; do
    /usr/sbin/swapoff ${i};
  done

  for i in /sys/block/zram*; do
    /usr/bin/echo 1 > ${i}/reset;
  done
  [ -e /sys/module/zram ] && modprobe -r zram
}

case $1 in
  (start|stop) "$1" ;;
esac

最后

# systemctl enable zramswap
# systemctl start zramswap
# free -h

journal

是个好东西,接管日志,统一的格式,但是呢,时间长了,几个 GB 的日志还是挺占用空间的,需要配置下

手动清理日志

# journalctl --vacuum-time=1d
# journalctl --vacuum-size=100M

写入配置 /etc/systemd/journald.conf

SystemMaxUse=100M

ulimits on systemd

编辑 /etc/systemd/system.conf 或 /etc/systemd/user.conf,依据 unit 文件在哪个目录。

DefaultLimitNOFILE=51200
DefaultLimitNPROC=51200

升级 kernel ≥ 4.9

Linux Tovalds 于 2016 年 12 月 11 日发布了 Kernel 4.9 正式版本,带来了一些令人激动的特性以及一些驱动的更新。Linux 稳定内核维护者 Greg Kroah-Hartman 也早已宣布下一个长期支持版(LTS)内核将是 Linux 4.9。来自 Google 的 BBR (Bottleneck Bandwidth and RTT) TCP 拥塞控制 (congestion control) 算法也在这个版本并入了主线。为了体验 BBR TCP,迫不及待的需要将 CentOS 7 的内核升级至该版本。具体的更新可以查阅:Linux Kernel 4.9 release notes

安装

现在升级内核,没有那么复杂,也无需安装第三方源,在 CentOS-7.3.1611 之后用自带 repo 的即可,只需一行命令

# yum --enablerepo=centos-kernel update

或者编辑文件 /etc/yum.repos.d/CentOS-x86_64-kernel.repo ,在 [centos-kernel]

enabled=1

再更新系统

# yum update

更新完成后重启,通过 uname -a 查看内核版本,譬如我的

$ uname -a
Linux CentOS 4.9.13-203.el7.x86_64 #1 SMP Wed Mar 08 13:39:54 EST 2017 x86_64 x86_64 x86_64 GNU/Linux

一些 grub 操作内核的相关命令,可能用得到

awk -F\' '$1=="menuentry " {print i++ " : " $2}' /etc/grub2.cfg     # 查看 grub 中内核版本以及顺序
grub2-editenv list      # 当前默认的启动项
grub2-set-default N     # 设置你需要的内核版本为默认启动内核
开启 BBR TCP
echo "net.core.default_qdisc=fq" >> /etc/sysctl.conf
echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf

重启后,首先 uname -a 看下内核是否切换到 4.9,然后执行下面明亮查看内核是否开启 TCP BBR:

sysctl net.ipv4.tcp_available_congestion_control
sysctl net.ipv4.tcp_congestion_control

查看 tcp_bbr 模块是否加载:

lsmod | grep tcp_bbr
重新生成 rescue 镜像

这一步不是必须的。

确认下 /usr/lib/dracut/dracut.conf.d/02-rescue.conf 中的 dracut_rescue_image 是否为 yes,然后:

rm -f /boot/vmlinuz-0-rescue-* /boot/initramfs-0-rescue-*.img
/etc/kernel/postinst.d/51-dracut-rescue-postinst.sh $(uname -r) /boot/vmlinuz-$(uname -r)

Sass 的色彩函数

 

Sass 色彩相关的函数非常强大,当你定下页面基调色彩变量后,就可以大大的加快了开发速度,特别是对我这种半调子且没有任何色彩搭配概念的人来说,使用起来确实是轻松加愉快的。

废话不多说,下面开始,定下一个基本色,譬如咖啡色,更多色彩值

$base: chocolate;

这样定义有两个好处:

  • 涉及色彩的部分,可以非常容易的修改
  • 可以不用记住颜色值

Darken & Lighten

这两个是用来调整颜色的 HSL 值的亮度,顾名思义,Darken 变暗,Lighten 变亮。Sass 会自动的分析我们的颜色的 HSL 值来进行调整,用百分比来计算:

darken($base, 10%);
lighten($base, 10%);

Saturate & Desaturate

这两个将调整饱和度与去色,同样,Sass 会自动分析 HSL 值来进行调整,也需要百分比来表示:

saturate($base, 20%);
desaturate($base, 20%);

Adjust-hue

这将调整色彩的色相,同样通过百分比计算:

adjust-hue($base, 20%); 

Other

HSL 相关的函数还有很多,譬如

hsl($hue, $saturation, $lightness);
hsla($hue, $saturation, $lightness, $alpha);
hue($color);
saturation($color);
lightness($color);
grayscale($color);
complement($color);
invert($color);

除此以外,Sass 提供了其他有趣的函数,譬如 rgb 函数:

rgb($red, $green, $blue);
rgba($red, $green, $blue, $alpha);
red($color);
green($color);
blue($color);
mix($color1, $color2, [$weight]);

了解更多:http://sass-lang.com/documentation/Sass/Script/Functions.html

 
 
 
 

打包与解包安卓的img镜像文件

 如何解包/打包安卓的各类 img 文件。下面介绍/

首先可以去 https://android.googlesource.com/platform/system/extras 下载工具源代码

$ git clone https://android.googlesource.com/platform/system/extras /your/path

checkout 你需要的版本,譬如 android-5.1.1_r13

$ cd /your/path/extras
$ git checkout android-5.1.1_r13

编译 simg2img,这里你需要 gcc 工具,linux 用户基本都由现成的

$ cd /your/path/extras/ext4_utils
$ gcc -o simg2img -lz sparse_crc32.c simg2img.c
$ gcc -o make_ext4fs -lz make_ext4fs_main.c make_ext4fs.c ext4fixup.c ext4_utils.c allocate.c backed_block.c output_file.c contents.c extent.c indirect.c uuid.c sha1.c sparse_crc32.c wipe.c

当前目录会生成 simg2img 与 make_ext4fs 两进制文件

下面解包开始,以 system.img 为例

$ ./simg2img system.img system.ext4

随后,可以直接挂载,需要 root 权限

# mkdir /your/path/system-data
# mount -t ext4 -o loop system.ext4 /your/path/system-data

打包的话,则是如此操作

$ ./make_ext4fs -s -l 512M -a system system-data.img /your/path/system-data

或者使用源代码中的脚本

$ cd /your/path/extras
$ PATH="$PATH:$(pwd)/ext4_utils/make_ext4fs" ./ext4_utils/mkuserimg.sh -s /your/path/system-data system-data.img ext4 /tmp 512M

最后转换下

$ ./simg2img system-data.img system.img

OK,你可以刷入你的手机了,Good luck!

OS X 解包 pkg

 

刚用 OS X 的同学会发现,Mac OS X 的 App 安装包,有两种形式,一种就是 .app,可以直接运行,类似于 Windows 下的绿色版;另一种是 .pkg 安装包,需要一路 next 安装好后才能使用。

在 OS X 下,PKG 包的卸载非常不人性化,最讨厌的是,只要是个 pkg 安装包,基本都要请求 root 权限。

于是,网上溜达一圈,找到直接解包 pkg 文件的方法,获取有用部分来使用。

我们以招商银行的网银插件为例,下载获取 dmg 镜像文档:CMBSecurityPlugin.dmg,双击打开,将 CMB Security Plugin.pkg 文件拖出来。

现在我们来解包:

$ pkgutil --expand CMB\ Security\ Plugin.pkg CMB\ Security\ Plugin
$ cd CMB\ Security\ Plugin
$ ls -l
total 8
-rw-r--r--  1 havee  staff  2794 12 25  2012 Distribution
drwxr-xr-x  3 havee  staff   102  9  9 14:06 Resources
drwxr-xr-x  5 havee  staff   170  9  9 14:06 cmbsecurityplugin.pkg

实际上,CMB Security Plugin.pkg 本身就是一个 xar 包:

$ file CMB\ Security\ Plugin.pkg
CMB Security Plugin.pkg: xar archive - version 1

可以用如下命令直接解压:

$ mkdir CMB\ Security\ Plugin; cd CMB\ Security\ Plugin
$ xar -xf ../CMB\ Security\ Plugin.pkg
$ ls -l
total 8
-rw-r--r--  1 havee  staff  2794 12 25  2012 Distribution
drwxr-xr-x  3 havee  staff   102 12 25  2012 Resources
drwxr-xr-x  5 havee  staff   170 12 25  2012 cmbsecurityplugin.pkg

可以看到,以上两种方式,都可以解压。

接下来,我们看到,又出现一个 pkg 文件,再看下文件类型:

$ file cmbsecurityplugin.pkg
cmbsecurityplugin.pkg: directory

是一个文件夹,进去:

$ cd cmbsecurityplugin.pkg; ls -l
total 304
-rw-r--r--  1 havee  staff   36348 12 25  2012 Bom
-rw-r--r--  1 havee  staff     216 12 25  2012 PackageInfo
-rw-r--r--  1 havee  staff  114278 12 25  2012 Payload

对三个文件分别查看下类型:

$ file Bom
Bom: Mac OS X bill of materials (BOM) file
$ file PackageInfo
PackageInfo: ASCII text
$ file Payload
Payload: gzip compressed data, from Unix

可以看到,三个文件中 Payload 文件是一个 gzip 压缩包,解开看下:

$ tar xvf Payload
x .
x ./._.DS_Store
x ./CMBSecurity.plugin
x ./CMBSecurity.plugin/Contents
x ./CMBSecurity.plugin/Contents/embedded.provisionprofile
x ./CMBSecurity.plugin/Contents/Info.plist
x ./CMBSecurity.plugin/Contents/MacOS
x ./CMBSecurity.plugin/Contents/MacOS/CMBSecurity
x ./CMBSecurity.plugin/Contents/Resources
x ./CMBSecurity.plugin/Contents/Resources/en.lproj
x ./CMBSecurity.plugin/Contents/Resources/en.lproj/InfoPlist.strings
x ./Contents
x ./Contents/_CodeSignature
x ./Contents/_CodeSignature/CodeResources
x ./Contents/embedded.provisionprofile
x ./Contents/Info.plist
x ./Contents/MacOS
x ./Contents/MacOS/CMBSecurity
x ./Contents/Resources
x ./Contents/Resources/en.lproj
x ./Contents/Resources/en.lproj/InfoPlist.strings

OK,至此,我们得到了招商银行大众版网银插件 CMBSecurity.plugin,直接复制到 ~/Library/Internet Plug-Ins/ 目录下即可。

总结下,三步走:

$ pkgutil --expand "name.pkg" "name"
$ cd name/package.pkg/
$ tar xvf Payload

当然,有些 pkg 会附带证书、启动 plist 文件等等,需要具体情况具体分析。

----------------------------------------------------------------------------------

OS X下,卸载 pkg 包

以下所说的只适用于 OS X Yosemite 下,之前的版本不做考虑。

一、准备

首先,安装的 pkg 软件包,都记录在以下

/Library/Receipts/InstallHistory.plist
/private/var/db/receipts

下面介绍的是一个命令工具:pkgutil

$ pkgutil -h
Usage: pkgutil [OPTIONS] [COMMANDS] ...

Options:
  --help                 Show this usage guide
  --verbose, -v          Show contextual information and format for easy reading
  --force, -f            Perform all operations without asking for confirmation
  --volume PATH          Perform all operations on the specified volume
  --edit-pkg PKGID       Adjust properties of package PKGID using --learn PATH
  --only-files           List only files (not directories) in --files listing
  --only-dirs            List only directories (not files) in --files listing
  --regexp               Try all PKGID arguments as regular expressions

Receipt Database Commands:
  --pkgs, --packages     List all currently installed package IDs on --volume
  --pkgs-plist           List all package IDs on --volume in plist format
  --pkgs=REGEXP          List package IDs on --volume that match REGEXP
  --groups               List all GROUPIDs on --volume
  --groups-plist         List all GROUPIDs on --volume in plist format
  --group-pkgs GROUPID   List all PKGIDs in GROUPID
  --files PKGID          List files installed by the specified package
  --lsbom PKGID          List files in the same format as 'lsbom -s'
  --pkg-groups PKGID     List all GROUPIDs that PKGID is a member of
  --export-plist PKGID   Print all info about PKGID in plist format
  --verify PKGID         Verify file permissions of the specified package
  --repair PKGID         Repair file permissions of the specified package
  --pkg-info PKGID       Show metadata about PKGID
  --pkg-info-plist PKGID Show metadata about PKGID in plist format
  --file-info PATH       Show metadata known about PATH
  --file-info-plist PATH Show metadata known about PATH in plist format
  --forget PKGID         Discard receipt data for the specified package
  --learn PATH           Update --edit-pkg PKGID with actual metadata from PATH

File Commands:
  --expand PKG DIR       Expand the flat package PKG to DIR
  --flatten DIR PKG      Flatten the files at DIR as PKG
  --bom PATH             Extract any Bom files from the pkg at PATH into /tmp
  --payload-files PATH   List the paths archived within the (m)pkg at PATH

二、方法

pkgutil 的帮助文件已经说明的很清楚了,步骤:

1. 查找下你需要卸载的软件包ID
$ pkgutil --pkgs
2.列出该 pkg 包含的文件列表
$ pkgutil --files PKGID
3. 检查下软件包信息,路径
$ pkgutil --pkg-info PKGID

譬如招行的插件信息

$ pkgutil --pkg-info com.cmbchina.CMBSecurityPlugin.pkg
package-id: com.cmbchina.CMBSecurityPlugin.pkg
version: 1.0
volume: /
location: Library/Internet Plug-Ins
install-time: 1401513557

从以上我们要获取的信息是,PKGID 为 com.cmbchina.CMBSecurityPlugin.pkg,在根目录 / 下的 Library/Internet Plug-Ins 目录,也就是 /Library/Internet Plug-Ins 目录下,这个下面用得到。

4. 执行删除操作

你当然可以通过 pkgutil --files PKGID 得到的文件列表,手动的去删除,我们还是读软件包的 bom 文件去删除,仍然以招行插件为例:

$ lsbom -fls  /private/var/db/receipts/com.cmbchina.CMBSecurityPlugin.pkg.bom | (cd /Library/Internet\ Plug-Ins; sudo xargs rm)
$ lsbom -dls  /private/var/db/receipts/com.cmbchina.CMBSecurityPlugin.pkg.bom | (cd /Library/Internet\ Plug-Ins; sudo xargs rm -r)

cd 路径,即第 3 步中的目录。

lsbom 的具体用法可以参考 lsbom --help

5. 最后清除包管理数据库中的pkg包信息
$ sudo pkgutil --forget PKGID

三、App

上面的都是一些基础的介绍,当然如今已经有现成的 app 可以使用,譬如 PackageUninstallerUninstallPKG,前者免费,后者收费。

参考:

 

Linux 系统的 NTFS-3G 权限

 

一般情况下,我们在 Linux 下挂载 ntfs,是安装 ntfs-3g 后进行的,即:

# mount -t ntfs-3g /dev/sdb1 /mnt/data

这样临时解决下可以,但是会涉及到权限问题,就是说,/mnt/data 下的所有文件都必须 root 权限。于是我们加入一些参数让当前用户也可以访问修改:

# mount -t ntfs-3g -o uid=username,gid=users /dev/sdb1 /mnt/data      # uid 为当前用户名,gid 为users 用户组

一般人到此为止,临时需求嘛,不过强迫症表示,看到挂载的分区,所有文件都是 777 权限表示非常不爽,于是:

# mount -t ntfs-3g -o uid=username,gid=users,umask=022 /dev/sdb1 /mnt/data

umask 表示,去掉的权限。

SUGO

说到这里,补充下 Linux 的权限表示为 SUGO,第一位 s 表示 SUIDSGIDSticky bit,一般用不到,后面附录顺带提一下,这里说下 UGO,三个位置,每个都用 rwx 来表示所拥有的权限,rwx 分别表示,读、写、执行(访问),分别用数字 4、2、1来表示,对应关系如下:

拥有者(U) 群组(G) 其他(O) 相应数字权限
r w x r w x r w x 权限
4 2 1 4 2 1 4 2 1 777
4 2 1 4 0 1 4 0 1 755
4 2 1 4 2 1 4 0 0 774
4 2 1 0 0 0 0 0 0 700
4 2 0 4 0 0 4 0 0 644

如此就明了,644 表示 U(User) 拥有读写权限,G(Group) 拥有只读权限,O(Other) 拥有只读权限。

umask、fmask、dmask

  • umask – 过滤目录与文件的权限
  • fmask – 过滤文件的权限
  • dmask – 过滤目录的权限

描述很清楚了,如果你想拥有 755 权限,那么 权限 = 777 - 022,每一位相减,得到 755,就是说,umask = 022 后,实际权限为 755,fmask、dmask 同理,如果想拥有 644 呢, 644 = 777- 133……

现在清楚了,上文我们设置的 umask=022,实际上,所有文件文件的权限也都被设置为 755 了,这对于拥有 wine 的用户来说,不是一个好消息,那么我们就分别来设置 fmask 与 dmask。

# mount -t ntfs-3g -o uid=username,gid=users,fmask=133,dmask=022 /dev/sdb1 /mnt/data

于是,我们最终得到的文件权限为 644,文件夹权限为 755,以上写入 fstab 中一开机就挂载的话,就是如此:

/dev/sdb1 /mnt/data ntfs-3g uid=username,gid=users,fmask=133,dmask=022 0 0

附录

SUGO 中的 S,表示 SUID、SGID、Sticky bit 之和,而 SUID、SGID、Sticky bit 分别用 4、2、1 来表示相关权限。

即:

SUID+SGID+Sticky bit 之和 表示
4 + 2 + 1 7 SUID + SGID + Sticky bit
4 + 2 + 0 6 SUID + SGID
4 + 0 + 1 5 SUID + Sticky bit
4 + 0 + 0 4 SUID
0 + 2 + 1 3 SGID + Sticky bit
0 + 2 + 0 2 SGID
0 + 0 + 1 1 Sticky bit
0 + 0 + 0 0

应用场景很多人都提过的,/etc/shadow 为 root 读写,普通用户也可以使用 passwd 来更改自己密码的原因。

  • SUID: 只能作用在可执行文件上,当其他用户运行改执行文件时,会临时拥有该文件所有者的权限
  • SGID: 可以作用在目录或可执行文件上,也同样,临时拥有该文件或文件夹所有者的权限
  • Sticky bit: 只能作用在目录,可以用来防删除,一旦拥有 Sticky bit 属性是,除了目录所有者与 root,其他任何人都无法删除该目录下文件或子目录。

参考:

Docker容器使用小结

Docker 是一个开源的应用容器引擎,使用轻量级的容器虚拟化技术,开发者可以方便的打包他们的应用以及依赖包到一个可移植的容器中,来发布到任何流行的 Linux 发行版上。

  • 命名空间: Docker 引擎采用 namespaces 来提供一个隔离的工作区,通过 kernel 的 pid、net、ipc、mnt、uts 等 namespaces 实现对进程、网络、消息、文件系统以及 HostName/DomainName 的隔离。
  • 资源配置:通过 cgroups 来控制容器的硬件资源。
  • 文件系统:利用 UnionFS,通过创建图层来实现对容器的轻量与快速更新。Docker 引擎可以使用多个 UnionFS 的变种,包括 AUFS、btrfs、vfs 与 DeviceMapper。
  • 容器格式:Docker 引擎结合 namespaces、cgroups、UnionFS 一起组成 libcontainer 容器格式,将来或许会支持更多的譬如 BSD Jails、Solaris Zones 容器格式。

Docker 已经成熟并被大量的应用到生产环境,所以概念部分就不阐述了,针对与 Virtual Machines 的区别说一下。

Docker 的出现,并非是为了取代 Virtual Machine,前者是为了 devops,后者则是为了统一开发环境。Docker 是一个容器,底层的实现是利用下层操作系统内核提供的功能,是进程级别的。而 VM 则是完全的虚拟化,底层则基本是虚拟机.

使用方法

很多人对概念部分不感冒,还是让我们直接进入使用环节,详细的参数,可以通过 docker COMMAND --help 来获取详细信息。

安装
  • Linux: 使用各发行版的包管理工具即可安装
  • Mac: Docker for Mac
  • Windows: Docker for Windows
试运行

我们在 Docker 容器中运行一个 echo 试试,首先拉取一个远程的 apline 镜像,其次容器中输出 “Hello World!”。

docker pull alpine
docker run -it apline echo "Hello World!"

是的,一个基于 Alpine 的镜像按照你的命令输出了 “Hello World”。我们查看下本地现有的镜像:

$ docker images -a
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
alpine              latest              4e38e38c8ce0        12 weeks ago        4.799 MB

查看下本地现有的 Docker 进程:

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS                     PORTS               NAMES
aaa36d3bc66e        alpine              "echo 'Hello World'"   4 seconds ago       Exited (0) 2 seconds ago                       distracted_meitner

我们销毁该进程后,再查看下:

$ docker rm aaa36d3bc66e
aaa36d3bc66e
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

我们如何进入容器中呢,譬如查看下镜像的内核与版本,然后退出并销毁该进程:

$ docker run -it alpine sh
/ # uname -a
Linux f35ec3b5e253 4.4.15-moby #1 SMP Thu Jul 28 22:03:07 UTC 2016 x86_64 Linux
/ # cat /etc/alpine-release
3.4.0
/ # exit
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
c50ffeb5a709        alpine              "sh"                12 seconds ago      Exited (0) 1 seconds ago                       berserk_blackwell
$ docker rm c50ffeb5a709
c50ffeb5a709

我们把镜像也删除了吧:

$ docker rmi 4e38e38c8ce0
Untagged: alpine:latest
Untagged: alpine@sha256:3dcdb92d7432d56604d4545cbd324b14e647b313626d99b889d0626de158f73a
Deleted: sha256:4e38e38c8ce0b8d9041a9c4fefe786631d1416225e13b0bfe8cfa2321aec4bba
Deleted: sha256:4fe15f8d0ae69e169824f25f1d4da3015a48feeeeebb265cd2e328e15c6a869f

到这里,可以仔细观察下, container id 与 image id 的区别。

一般情况下,我们以 backgroud 运行一个容器,有时需要 attach 进容器进行一些操作,我们以 gists/nginx:stable 为例:

$ docker run --name my-nginx -d gists/nginx:stable
Unable to find image 'gists/nginx:stable' locally
stable: Pulling from gists/nginx
e110a4a17941: Pull complete
617dca60f103: Pull complete
b397f6ce6faa: Pull complete
09010597eddf: Pull complete
8ee5e0c70a8d: Pull complete
Digest: sha256:f8ed78c176be524fdb3e4193d6b6d36126745ab950b8f5e9d62186e598bd2660
Status: Downloaded newer image for gists/nginx:stable
72073c6d85cf3904201ccaff5fc9eb70525b5f57d010f43961047f4f03fb922b
$ docker exec -it my-nginx sh
/ #
/ # top
Mem: 341868K used, 1706792K free, 183572K shrd, 8692K buff, 190432K cached
CPU:   0% usr   0% sys   0% nic 100% idle   0% io   0% irq   0% sirq
Load average: 0.00 0.00 0.00 2/150 13
  PID  PPID USER     STAT   VSZ %VSZ CPU %CPU COMMAND
    6     1 nobody   S    34260   2%   1   0% nginx: worker process
    5     1 nobody   S    34260   2%   1   0% nginx: worker process
    1     0 root     S    13444   1%   0   0% nginx: master process nginx -g daemon off;
    7     0 root     S     1524   0%   1   0% sh
   13     7 root     R     1516   0%   1   0% top
/ # exit
$

构建镜像

还是让我们直接以 Dockerfile 来入门讲解:

FROM <image>:<tag>
MAINTAINER <name>

ENV <key> <value>

RUN command

COPY <src> <dest>

EXPOSE <port>

VOLUME ["/path/to/dir"]

USER <username>

WORKDIR /path/to/dir

CMD yourcommand
  • FROM:Dockerfile 文件的第一条指令,当前镜像构建于哪个镜像,现在一般以 apline 即基础镜像。
  • MAINTAINER:指定维护者信息。
  • ENV:环境变量,被后续 RUN 等指令使用,并在容器运行时保持。
  • RUN:构建镜像的详细指令,每多一条 RUN 指令即多一层 layer。
  • COPY:复制 Dockerfile 文件所在目录中的文件或目录到容器中。
  • ADD:复制 Dockerfile 所在目录中的文件到容器中,也可以是一个 URL,还可以自动解压 tar。
  • EXPOSE:指定暴露给 Host 的端口号,可以如下几种形式,第三种是指定端口范围:
    • EXPOSE port1 port2
    • EXPOSE port1/tcp port2/udp
    • EXPOSE port1:port2
  • VOLUME:创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。
  • USER:指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。当服务不需要管理员权限时,可以通过该命令指定运行用户。
  • WORKDIR:为后续的指令指定工作目录。
  • ENTRYPOINT:指定容器启动后的命令,不可被 docker run 提供的参数覆盖,有两种格式:
    • ENTRYPOINT [“executable”, “param1”, “param2”]
    • ENTRYPOINT command param1 param2
  • CMD:指定容器服务运行时的命令,有三种格式:
    • CMD [“executable”,”param1”,”param2”]
    • CMD command param1 param2
    • CMD [“param1”,”param2”] 提供给 ENTRYPOINT 的默认参数

最后通过在 Dockerfile 目录执行 docker build . 来构建镜像。

说到这里,提一下我构建镜像的方法,我现在基本是以 Alpine Linux 为基础镜像,docker run -it --name test alpine:3.4 sh 进入交互模式,将需要安装的服务在 shell 下一步一步去安装去配置,一切顺利后,再将步骤写入 Dockerfile 的 RUN 指令中。再 docker build .docker run .. 跑一遍,确认无误后,才会 push,最后通过 docker hub 的自动构建镜像。

目前,个人制作的公开镜像地址:https://hub.docker.com/r/gists/

运行时资源限制

选项 描述
-m,--memory="" 物理内存限制,单位 b、k、m 或 g,最小值 4m
--memory-swap="" 内存限制(memory + swap),同上,当值等于 --memory 时,表示禁用 swap,值为 -1 时表示不限制
--memory-reservation="" 内存软限制,单位同上
--kernel-memory="" 内核内存限制,单位同上,最小值 4m
-c, --cpu-shares=0 CPU 利用率权重,0 为忽略,默认为单核 1024
--cpu-period=0 指定时钟周期内(μs 微秒)的 CPU 的使用需要重新分配一次,最小值 1000,默认值 100000
--cpuset-cpus="" 设置容器允许使用的cpu,譬如允许容器使用双核,--cpuset-cpus="0,1"
--cpuset-mems="0-2" 应用于 numa 架构的 CPU,允许执行存储器节点 (0,1,2)
--cpu-quota=0 指定 --cpu-period="" 的时钟周期内有多少时间(μs 微秒)运行,默认值 -1,即不做控制
--blkio-weight=0 容器默认磁盘 IO 的加权值,有效值范围为 10-1000
--blkio-weight-device="" 针对特定设备的 IO 加权控制。其格式为 DEVICE_NAME:WEIGHT
--device-read-bps="" 限制此设备上的读速度,单位 kb、mb 或 gb
--device-write-bps="" 限制此设备上的写速度,单位 kb、mb 或 gb
--device-read-iops="" 通过每秒读 IO 次数来限制指定设备的读速度
--device-write-iops="" 通过每秒写 IO 次数来限制指定设备的写速度
--oom-kill-disable=false 是否允许 OOM Killer
--oom-score-adj=0 配置 OOM (-1000 to 1000)
--memory-swappiness="" 控制进程将物理内存交换到 swap 的意向,越小越倾向于使用物理内存,当为 0 时,表示不加任何限制,而不是禁用swap
--shm-size="" /dev/shm 大小,单位 b、k、m、g,值必须为大于 0

运行 GUI 镜像

Docker 当然可以运行 GUI 镜像,譬如 Firefox,让我们直观的认识下 Firefox 的 Dockerfile:

FROM alpine:edge

RUN set -xe && \
    echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && \
    apk add --no-cache \
                    firefox \
                    libcanberra-gtk3 \
                    dbus-x11 \
                    libstdc++ \
                    libgcc \
                    musl \
                    ttf-dejavu && \
    addgroup -g 1000 -S firefox && \
    adduser -u 1000 -G firefox -h /home/firefox -D firefox

USER firefox

CMD ["/usr/bin/firefox", "-new-instance"]

这是我写的一个简单的 Firefox 的 Dockerfile,如何运行呢

docker run \
    -d \
    --name firefox \
    -e DISPLAY=$DISPLAY \
    -v /tmp/.X11-unix:/tmp/.X11-unix
    -v /dev/snd:/dev/snd
    gists/firefox

注意:运行 docker run 之前,你需要允许 docker 用户的 X server 权限

xhost +local:docker

CentOS 下,docker 是以 root 运行的,所以需要

xhost +local:root
xhost 一些衍生

xhost 是用来控制 X server 访问权限的。通常当你从 hostA 登陆到 hostB 上运行 hostB 上的应用程序时,做为应用程序来说,hostA 是 client,但是对图形来说,是在 hostA 上显示的,需要使用 hostA 的 Xserver,所以 hostA 是 server。因此在登陆到 hostB 前,需要在 hostA 上运行 xhost +user 来使其它用户能够访问 hostA 的 Xserver。

具体用法:

xhost +/- Name,Name 语法:family:name
xhost +: 是使所有用户都能访问 Xserver
xhost +ip: 使 ip 上的用户能够访问 Xserver
xhost +nis:user@domain: 使 domain 上的 nis 用户 user 能够访问
xhost +inet:user@domain: 使 domain 上的 inet 用户能够访问
xhost +local:wheel: 使本地用户wheel 能够访问

镜像导入导出

docker save imageID -o name.tar
docker load -i name.tar
docker tag imageID name:tag

容器导入导出

docker export containerID > name.tar
docker import name.tar
docker tag imageID name:tag

群集模式

https://docs.docker.com/engine/reference/commandline/swarm/

swarm 在现在的 docker 中是内建的,直接可以开启

创建

docker swarm init
docker swarm join-token worker
docker swarm join-token manager

让其他 docker 加入该集群,可以按照提示操作,可以选择加入 worker 还是 manager

如果有防火墙,注意开启如下防火墙端口

协议 端口 描述
tcp 2377 集群管理通信
tcp & udp 7946 节点间通信
udp 4789 overlay 网络
esp all overlay 加密网络

譬如 iptables

iptables -A INPUT -p tcp -m conntrack --ctstate NEW -m tcp --dport 2377 -j ACCEPT
iptables -A INPUT -p udp -m conntrack --ctstate NEW -m udp --dport 4789 -j ACCEPT
iptables -A INPUT -p tcp -m conntrack --ctstate NEW -m tcp --dport 7946 -j ACCEPT
iptables -A INPUT -p udp -m conntrack --ctstate NEW -m udp --dport 7946 -j ACCEPT
iptables -A INPUT -p esp -j ACCEPT

譬如 nftables

nft add rule inet filter input tcp dport 2377 accept
nft add rule inet filter input udp dport 4789 accpet
nft add rule inet filter input tcp dport 7946 accpet
nft add rule inet filter input udp dport 7946 accept
nft add rule inet filter input ip protocol esp accept
stack
docker stack deploy -c ./docker-compose.yml name
docker stack rm name

more: https://docs.docker.com/engine/reference/commandline/stack/

node
docker node update --label-add zone=name node_id
docker node update --label-rm zone=name node_id

more: https://docs.docker.com/engine/reference/commandline/node/

service update
docker service update --replicas=3 service_name

more: https://docs.docker.com/engine/reference/commandline/service/

dockerhub

登陆 dockerhub 网站,获取 access tokens 后

echo xxxxxxxxxxxxxxxx | docker login -u username --password-stdin

打开试验性功能,方便 buildx 等试验性功能

~/.docker/config.json
{
    "experimental": "enabled"
}

未完待续……

参考: https://docs.docker.com