2018年1月25日 星期四

檔案與目錄的管理

每個檔案的參用係透過一個inode(資訊節點);inode即是一個實際的物件,
也是一個概念係實體(由Linux核心裡的一個資料結構來表示)inode可用來儲存與某個檔案有關的中介資料(metadata),例如檔案的存取權限、上一次的存取時間戳記、擁有者、群組、長度
以及檔案之資料的擺放位置但不包含檔案的名稱,
檔案名稱是存放在目錄項目(directory entry)

$ ls -i
       -i, --inode
              print the index number of each file
-------------------------------------------------------
stat, fstat, lstat - get file status
       int stat(const char *path, struct stat *buf);
       int fstat(int fd, struct stat *buf);
       int lstat(const char *path, struct stat *buf);

struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* inode number */ mode_t st_mode; /* protection */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ dev_t st_rdev; /* device ID (if special file) */ off_t st_size; /* total size, in bytes */ blksize_t st_blksize; /* blocksize for filesystem I/O */ blkcnt_t st_blocks; /* number of 512B blocks allocated */ time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of last status change */ };


Linux系統並未保存建立的時間
-------------------------------------------------------
chmod, fchmod - change permissions of a file

       int chmod(const char *path, mode_t mode);

       int fchmod(int fd, mode_t mode);

-------------------------------------------------------
chown, fchown, lchown - change ownership of a file
       int chown(const char *path, uid_t owner, gid_t group);
       int fchown(int fd, uid_t owner, gid_t group);
       int lchown(const char *path, uid_t owner, gid_t group);
-------------------------------------------------------
xattr - Extended attributes
提供一個機制可用於把鍵/值對(key/value pair)關聯到檔案
延伸屬性讓現有的檔案系統得以支援原始設計中未提供的功能
Think: 是否可以透過xattr來記檔案建立的時間!?
fatal error: attr/xattr.h: No such file or directory
apt-get install libattr1-dev
-------------------------------------------------------
目錄Directory包含了一串檔案名稱,每個檔案名稱會被對映到一個inode編號
每個名稱又稱為一個目錄項目(directory entry)
而且每個名稱至inode的映射稱為一個連結(link)
每個目錄包含兩個特殊目錄: 
.」dot(點)目錄用於參照目錄本身
..」dot-dot(點點)目錄則用於參照目錄的父目錄

getcwd, get_current_dir_name - get current working directory

       char *getcwd(char *buf, size_t size);

       char *get_current_dir_name(void);
如果buf為NULL,Linux的C函式庫會分配一個長度size個位元組的緩衝區,
而且會把當前工作目錄儲存在該處。如果size為0
C函式庫會分配一個足以儲存當前目錄的緩衝區
然後應用程式的責任是在它完成工作後,經由free()釋出緩衝區
雷同get_current_dir_name()

chdir, fchdir - change working directory
mkdir / rmdir - create / delete a directory

       int chdir(const char *path);

       int fchdir(int fd);

       int mkdir(const char *pathname, mode_t mode);

       int rmdir(const char *pathname);



opendir / readdir / closedir - open / read / close a directory

       DIR *opendir(const char *name);

       struct dirent *readdir(DIR *dirp);

       int closedir(DIR *dirp);



      //dirent結構代表一個目錄項目(directory entry)

           struct dirent
               ino_t                 d_ino;               /* inode number */
               off_t                  d_off;                /* not an offset; see NOTES */
               unsigned short d_reclen;          /* length of this record */
               unsigned char  d_type;             /* type of file; not supported
                                                                    by all filesystem types */
               char                 d_name[256];  /* filename */
           };

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

硬連結(Hard Link)
可以把Hard Link當成源文件的副本,它顯示跟源文件一樣的大小但事實上卻不占任何空間。
並沒有另外建立一個inode,不可跨檔案系統
$ ln orig_file hardlink_file

符號連結(Symbolic Link)
可以把Symbolic Link當成快捷跨檔案系統
$ ln -s orig_file softlink_file
$ ls -i

2430961 -rw-rw-r-- 2 bh0322 bh0322    237 Jan 24 09:25 hardlink_file

2430951 lrwxrwxrwx 1 bh0322 bh0322   13 Jan 25 02:08 softlink_file -> orig_file

2430961 -rw-rw-r-- 2 bh0322 bh0322    237 Jan 24 09:25 orig_file

如果orig_file被刪除掉,softlink_file會找不到orig_file,hardlink_file不會受影響

link - make a new name for a file
symlink - make a new name for a file
unlink - delete a name and possibly the file it refers to
       int link(const char *oldpath, const char *newpath);
       int symlink(const char *oldpath, const char *newpath);
       int unlink(const char *pathname);
為了避免肆意破壞任何類型的檔案,C語言提供了remove()函式:
remove - remove a file or directory
       int remove(const char *pathname);
remove() deletes a name from the filesystem.  It calls unlink(2) for files, and rmdir(2) for directories.
-------------------------------------------------------
device node是存取硬體的標準機制
每個裝置節點會被指定兩個數值,稱為主要編號(major number)及次要編號(minor number)
這些主要和次要編號會映射至被載入核心的特定裝置驅動程式
特殊裝置節點:
1. crw-rw-rw- 1 root root 1, 3 Aug 28 02:23 /dev/null
核心會靜靜丟棄針對該裝置檔的所有寫入要求。(黑洞) 例如把 fd 0 1 2都導入黑洞
針對該裝置檔的所有的讀取要求,核心會傳回end-of-file (EOF)
(1) 重新導向
$ cat file 2>/dev/null
$ find / -name XXX 2>/dev/null
(2) 清空文件內容
$ cat /dev/null > file

2. crw-rw-rw- 1 root root 1, 5 Aug 28 02:23 /dev/zero
核心會靜靜丟棄針對該裝置檔的所有寫入要求。(dummy files or swap)
針對該裝置檔的所有的讀取要求,核心會傳回null位元組的無窮串流
(1) 產生一個特定大小的空白文件
$ dd if=/dev/zero of=test.txt bs=1k count=1 1+0 records in 1+0 records out 1024 bytes (1.0 kB) copied, 0.000159227 s, 6.4 MB/s

$ dd if=/dev/null of=test.txt bs=1k count=1 0+0 records in 0+0 records out 0 bytes (0 B) copied, 0.00011535 s, 0.0 kB/s
Difference between /dev/null and /dev/zero

3. crw-rw-rw- 1 root root 1, 7 Aug 28 02:23 /dev/full

亂數產生器
核心的亂數產生器會從裝置驅動程式以及其他源頭收集noise(雜亂的資料),
而且核心會把收集到的noise連結在一起,並且對它進行單向雜湊運算
所得到的結果然後會被存入一個熵集區(entropy pool)
核心會不斷估算集區中熵的位元數目
4. crw-rw-rw- 1 root root 1, 8 Aug 28 02:23 /dev/random
5. crw-rw-rw- 1 root root 1, 9 Aug 28 02:23 /dev/urandom 「unblocked」


$ dd if=/dev/random of=random.dat bs=1024b count=1
0+1 records in
0+1 records out
28 bytes (28 B) copied, 0.000360786 s, 77.6 kB/s


$ dd if=/dev/urandom of=urandom.dat bs=1024b count=1
1+0 records in
1+0 records out
524288 bytes (524 kB) copied, 0.0499055 s, 10.5 MB/s


-rw-rw-r-- 1 bh0322 bh0322      28 Jan 25 06:39 random.dat

-rw-rw-r-- 1 bh0322 bh0322 524288 Jan 25 06:40 urandom.dat
可以看到使用/dev/random產生隨機數的速度很慢,而且產生的量很有限,
當然,/dev/urandom的隨機效果則好很多。

(1) 產生亂數的IP位置
od -vAn -N4 -tu4 /dev/urandom

(2) 隨機MAC位置
dd if=/dev/urandom bs=1 count=6 2> /dev/null | od -t x1 | sed '2d;s/^0\+ //;s/ /:/g'


/proc/sys/kernel/random/ ├── boot_id ├── entropy_avail ├── poolsize ├── read_wakeup_threshold ├── urandom_min_reseed_secs ├── uuid └── write_wakeup_threshold

rand, rand_r, srand - pseudo-random number generator
C 裡面使用 rand() 可以產生變數。但是每次傳回的解果都是一樣的。
所以我們可以加上 srand(time(0)),藉由時間來取得亂數總子。
但這樣的亂數種子每秒變動一次。所以如果需要在一秒之內取得多個亂數則會有問題

int main()
{
   FILE *fp;
   int randno;

   if ((fp = fopen("/dev/urandom", "r")) == NULL) {
   fprintf(stderr, "Error! Could not open /dev/urandom for read\n");
    return -1;
   }

   randno = fgetc(fp);
   fclose(fp);

   return 0;
}

random, srandom, initstate, setstate - random number generator
getrandom - obtain a series of random bytes

getrandom() was introduced in version 3.17 of the Linux kernel. Support was added to glibc in version 2.25.
/*
* Add device- or boot-specific data to the input and nonblocking
* pools to help initialize them to unique values.
*
* None of this adds any entropy, it is meant to avoid the
* problem of the nonblocking pool having similar initial state
* across largely identical devices.
*/

void add_device_randomness(const void *buf, unsigned int size)

Bash內建變數
$ echo $RANDOM
-------------------------------------------------------
監控檔案事件
inotify可用於監控檔案-監視檔案何時被移動、讀取、寫入或刪除

2018年1月4日 星期四

Docker

Docker - Build, Ship, and Run Any App, Anywhere
透過對應用程式的封裝(Packaging)、分派(Distribution)、部署(Deployment)、運行(Runtime)
生命週期進行管理,達到應用系統元件一次封裝,隨處運行」的目標
這裡的應用系統元件,即可以是一個Web應用一套編譯環境
也可以是整套資料庫平台服務甚至是一個作業系統或叢集



Container VS Virtual Machine Docker以及其他容器技術都屬於作業系統及虛擬化。核心透過建立多個虛擬的作業系統實例
(Instances,包含應用程式和相關函式庫)來隔離不同的程序
Docker問世的目的,不只是為了讓應用程式可以到處部署,還希望可以比VM更善用系統資源,
不要再透過一層Guest OS來執行程式碼。


=========================================================
基本概念與安裝設定
Docker三大核心概念: 映像檔(Image), 容器(Container), 倉庫(Repository)
(1) Docker映像檔類似虛擬機映像檔,可以包含一個基本的作業系統環境,
裡面僅安裝了Apache應用程式(或使用者需要的其他軟體)。可以把它稱為一個Apache映像檔

(2) Docker容器類似一個輕量級的沙箱(sandbox),Docker利用容器來運行和隔離應用。
容器是用映像檔所創造的執行實例(Instance)。可以將其建立、開始、停止、刪除,
每個容器內運行著一個應用程式,不同的容器相互隔離容器之間也可透過網路互相溝通。
可以把容器看作是一個簡易版的Linux系統環境(包括root使用者權限、
PID Namespace程序命名空間、User Namespace使用者空間和Network Namespace網路)

(3) Docker倉庫類似於程式碼儲存庫,它是Docker集中存放映像檔的場所
倉庫註冊伺服器是存放倉庫的地方,上面往往存放著多個倉庫
每個倉庫集中存放某一類映像檔,通常包括多個映像檔,透過不同的tag來進行區分
例如存放Ubuntu作業系統映像檔的倉庫,稱為Ubuntu倉庫,其中可能包括14.04、12.04
等不同版本的映像檔

私有倉庫代管服務:
=========================================================
//Get Docker Community Edition (CE) for Ubuntu Trusty 14.04
https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/
$ sudo apt-get update
$ sudo apt-get install linux-image-extra-$(uname -r) linux-image-extra-virtual
$ sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88
pub   4096R/0EBFCD88 2017-02-22
     Key fingerprint = 9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid                  Docker Release (CE deb) <docker@docker.com>
sub   4096R/F273FCD8 2017-02-22
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
$ sudo apt-get update
sudo apt-get install docker-ce
$ sudo docker run hello-world

$ sudo docker version
Client:
 Version: 17.12.0-ce
 API version: 1.35
 Go version: go1.9.2
 Git commit: c97c6d6
 Built: Wed Dec 27 20:10:36 2017
 OS/Arch: linux/amd64

Server:
 Engine:
  Version: 17.12.0-ce
  API version: 1.35 (minimum version 1.12)
  Go version: go1.9.2
  Git commit: c97c6d6
  Built: Wed Dec 27 20:09:12 2017
  OS/Arch: linux/amd64
  Experimental: false

將目前使用者加入到安裝時自動建立的docker用戶群組
$ sudo usermod -aG docker bh0322

$ sudo service docker start
start: Job is already running: docker
$ sudo service docker status
docker start/running, process 84943
$ ps aux | grep 84943
root      84943  0.1  0.0 1353696 62024 ?       Ssl  10:20   0:01 /usr/bin/dockerd --raw-logs

$ sudo service docker restart
docker stop/waiting
docker start/running, process 67438

/etc/default/docker
/etc/init.d/docker
/var/run/docker.pid
/etc/init/docker.conf
/var/log/upstart/docker.log
=========================================================
Pull an image or a repository from a registry
docker pull [OPTIONS] NAME[:TAG|@DIGEST]
Options:
  -a, --all-tags=true|false                Download all tagged images in the repository (default false)
$ docker pull ubuntu:14.04
= docker pull registry.hub.docker.com/ubuntu:14.04
14.04: Pulling from library/ubuntu
050aa9ae81a9: Pull complete
1eb2c989bc04: Pull complete
f5e83780ccda: Pull complete
2dec31d7323c: Pull complete
286f32949bdc: Pull complete
Digest: sha256:084989eb923bd86dbf7e706d464cf3587274a826b484f75b69468c19f8ae354c
Status: Downloaded newer image for ubuntu:14.04
Image一般由數個資料層所組成,050aa9ae81a9這樣的字串是資料層唯一的ID
(實際上完整的ID包括256bits,由64個十六進制字元所組成)

$ docker pull gcr.io/tensorflow/tensorflow:latest-gpu

$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 00fd29ccc6f1 3 weeks ago 111MB ubuntu 14.04 67759a80360c 3 weeks ago 221MB gcr.io/tensorflow/tensorflow latest-gpu 12cea85b0ad7 4 weeks ago 3.36GB hello-world latest f2a91732366c 7 weeks ago 1.85kB
=========================================================
Run a command in a new container
   docker run [OPTIONS] IMAGE [COMMAND] [ARG...] [flags]
$ docker run -it gcr.io/tensorflow/tensorflow:latest-gpu bash
$ docker run -it ubuntu:14.04 bash

List containers
   docker ps [OPTIONS]
$ docker ps  (--no-trunc)
CONTAINER ID  IMAGE          COMMAND  CREATED                STATUS           PORTS               NAMES
d4cf3b40d12c   ubuntu:14.04  "bash"         About a minute ago  Up 59 seconds              compassionate_mirzakhani

Run a command in a running container
   docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
$ docker exec -it compassionate_mirzakhani bash

Display a live stream of container(s) resource usage statistics
   docker stats [OPTIONS] [CONTAINER...]
$ docker stats compassionate_mirzakhani
=========================================================

docker build -t goapp

$ docker search dpdk

$ docker pull brain4net/dpdk

$ docker build [OPTIONS] PATH | URL | - [flags]

簡單更新管理
使用Dockerfile,只需要小小的修改設定,就可以取代以往大量的更新工作。並且所有修改都以堆疊的方式進行派送和更新,進而實現自動化並且高效率的容器管理
Docker三劍客: Machine, Compose, Swarm
chroot -> Linux Container (LXC) -> Docker
導入Docker的關鍵是在軟體開發流程,而非技術或系統層面
Google推出Kubernetes (K8s)
Mesos, CoreOS
Azure PaaS
Azure Container Registry
CI/CD pipeline
Azure
AWS EC2 Container

【Docker通吃全平臺秘密武器】容器專屬超迷你OS包LinuxKit登場
LinuxKit是一個全容器化的超迷你Linux環境,目標是在任何OS中建立執行容器的環境,這正是Docker打通Linux和Windows壁壘的關鍵
Unikernel結合容器技術實作出LinuxKit專案,透過LinuxKit打造自己專屬的Linux Kernel
只包含執行該平台的必要元件,元件皆由容器所組成,可迅速移除替換,並適用於各種不同的環境

Q:Docker如何實現Container標準化?
A:Docker採用了aufs檔案系統來設計一個可以層層堆疊的Container映象檔,將Container內的所有程式(包括應用程式、相關函式庫、設定檔),都打包進Docker映象檔,並且提供了一個Dockerfile設定檔來記錄建立Container過程的每一個步驟包括參數。只要在任何支援Docker平臺的環境中,就可以從這個映象檔來建立出一個一模一樣的Container來執行同一個應用程式。如此一來,應用程式等於是可以透過Docker映象檔,或甚至只需要Dockerfile,就能將程式執行環境帶著走,移動到任何支援Docker的環境中。


Q:一個Container映象檔內可以安裝多少應用程式?
A:一個Container的映象檔內可以安裝多支程式,例如同時安裝Ubuntu、Apache、MySQL、Node.js、Ruby等。不過,Docker官方建議,一隻程式安裝在一個Container內,再把這些Container疊起來提供一個完整的服務。
Docker稱這是一種Microservices(微服務)的新軟體架構,將組成一個應用系統的每一個Stack,拆解成許多小型服務,例如Apache服務、MySQL服務、Node.js服務、Ruby服務,每一個服務都是包在Container裡的一隻程式,例如MySQL服務就是部署在Container內的MySQL。

這麼做的好處是可以建立一個鬆散耦合的彈性應用程式架構,也能輕易地抽換其中一個Container,例如要升級MySQL,只需要重新載入新版MySQL的Container映象檔,就可以完成資料庫升級,不用將整套應用系統停機。

Q:Docker對Devops有何幫助?
A:因為Docker透過Dockerfile來記錄建立Container映象檔的每一個步驟,
可以將建立應用程式執行環境的過程和配置參數,完整地記錄下來。
開發人員和維運人員之間可以利用Dockerfile來溝通對執行環境的討論。
甚至結合版本控制服務如GitHub,可以讓Dockerfile具備版本控制功能,
能將基礎架構程式化(Infrastructure as code)來管理。

Reference
https://docs.docker.com/engine/reference/commandline/stats/
https://www.gitbook.com/book/yeasy/docker_practice/details

Commands:
  attach      Attach local standard input, output, and error streams to a running container
  build        Build an image from a 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
  diff          Inspect changes to files or directories on a container's filesystem
  events      Get real time events from the server
  exec        Run a command in a running container
  export      Export a container's filesystem as a tar archive
  history      Show the history of an image
  images      List images
  import      Import the contents from a tarball to create a filesystem image
  info          Display system-wide information
  inspect     Return low-level information on Docker objects
  kill           Kill one or more running containers
  load         Load an image from a tar archive or STDIN
  login        Log in to a Docker registry
  logout      Log out from a Docker registry
  logs         Fetch the logs of a container
  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
  push        Push an image or a repository to a registry
  rename    Rename a container
  restart     Restart one or more containers
  rm           Remove one or more containers
  rmi          Remove one or more images
  run          Run a command in a new container
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
  search      Search the Docker Hub for images
  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
  tag          Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
  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
  wait         Block until one or more containers stop, then print their exit codes

$ sudo curl -sSL https://get.docker.com | sh
$ apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
$ lsb_release -c
Codename: trusty
$ sudo vim /etc/apt/sources.list.d/docker.list
deb https://apt.dockerproject.org/repo ubuntu-trusty main
$ sudo apt-get install docker.io

// Uninstall old versions
$ sudo apt-get remove docker docker-engine docker.io