Docker容器技術

什麼是Docker?

Docker是一個開源的引擎,能夠輕鬆的爲任何應用建立一個輕量級的、可移植的、自給自足的容器。開發者在筆記本上編譯測試經過的容器能夠批量地在生產環境中部署,包括VMs(虛擬機)、 bare metal、OpenStack 集羣和其餘的基礎應用平臺。(來自官方)

Docker的應用場景

1.產品交付:將環境和代碼打包成鏡像進行交付,交付更方便也更安全。
2.開發環境配置:將環境作成鏡像,開發人員直接啓動容器載入鏡像,開發環境就有了。
3.多版本測試:因爲Docker隔離了系統環境,同時容器直接互不影響,能夠啓動多個容器同時進行多版本的測試。
4.集羣環境部署:Docker能夠有效保證環境的一致,同時以容器爲單位部署服務更加方便,也有利於及時回滾和服務的遷移。
5.架構擴容和自動化運維:Docker快速啓動和低資源消耗的優勢在彈性雲平臺和自動化運維方面有很好的應用前景。

Docker的三大組件

1.容器:容器是服務運行的載體。容器爲服務虛擬出獨立的環境,容器之間互不影響。建立容器須要加載鏡像,容器自己也可打包爲鏡像。
2.鏡像:鏡像是容器狀態的快照。建立一個容器必需要有一個鏡像,好比centos鏡像、lnmp鏡像等。鏡像包含完整的應用和環境,啓動容器便可運行。
3.倉庫:倉庫是鏡像存放的地點。鏡像構建時須要指定倉庫,遠程倉庫能夠實現鏡像共享,例如DockerHub以及私有化倉庫Harbor。

Docker與Openstack的不一樣點

 
Docker
Openstack
部署難度
很是簡單,yum安裝docker便可
部署複雜,組件較多
啓動速度
秒級
分鐘級
處理性能
和物理機幾乎一致
有必定的性能損失
鏡像體積
MB級別
GB級別
管理效率
管理簡單
管理複雜,組件相互依賴
隔離性
不徹底隔離
完全隔離
進程數目
單進程、不建議啓動SSH
多進程,完整的系統管理
網絡鏈接
比較弱
Neutron組件能夠靈活構建網絡架構

Docker容器和虛擬機原理及性能比較

1.上圖分別是虛擬機和Docker容器的實現框架,顯然虛擬機比容器要多一個GuestOS操做系統層,因而獲得第一個區別:虛擬機調用的是完整的自身的操做系統內核,而Docker容器是直接調用物理機內核。
2.Hypervisor是一個硬件虛擬化平臺,它爲虛擬機內核提供底層驅動,因而獲得第二個區別:虛擬機的資源隔離是利用獨立OS和虛擬化硬件來實現,而DockerEngine則是利用物理機內核支持的LXC技術(LinuxContainer),經過namespace、cgroup等機制實現環境和資源的隔離。LXC是內核支持的一種輕量級虛擬化技術,與傳統虛擬化技術的最大的區別在於不須要解釋機制可直接在物理CPU中運行指令,LXC創建在cgroup基礎上,包括cgroup、namespace、chroot、veth以及用戶態控制腳本等。cgroup(control groups)是Linux內核提供的一種能夠限制、記錄進程組所使用物理資源的資源管理機制。namespace(命名空間)是Linux內核提供的一種資源隔離機制,將不一樣的進程和資源劃分在一個局部做用域內,內部的進程和資源只在當前做用域生效,相似於局部變量。
經過上面的比較,咱們能夠得出結論:
1.Docker直接調用物理機內核,而不須要GuestOS。所以,因爲不須要加載內核,建立一個容器只需幾秒鐘。同時,因爲不須要操做系統,docker更加節省資源。
2.Docker直接使用物理機硬件,比虛擬機有更少的抽象層。所以,docker的計算性能和效率幾乎和物理機相同。

Docker的優勢和缺點

1.優勢:Docker和虛擬機同樣能夠實現資源和環境的隔離,啓動速度快,資源消耗低,處理性能強。
2.缺點:Docker的資源隔離不如虛擬機完全,不能隔絕其餘程序佔用本身的資源。
       Docker不能分辨用戶權限,用戶只要能執行docker,就能夠對容器進行任何操做。
 

Docker快速入門

cat /etc/redhat-release
uname -rm
yum install -y docker
systemctl start docker
ifconfig  #docker啓動會建立一個虛擬網卡
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 0.0.0.0
        ether 02:42:55:0d:41:e1  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

docker images  #查看當前鏡像
docker search centos  #去dockerhub上搜索鏡像
INDEX       NAME                                         DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
docker.io   docker.io/centos                             The official build of CentOS.                   3625      [OK]
docker.io   docker.io/ansible/centos7-ansible            Ansible on Centos7                              100                  [OK]

docker pull centos  #獲取鏡像
docker load --input centos.tar   # 導入鏡像
docker save -o centos.tar centos  # 導出鏡像
docker rmi centos #刪除鏡像
docker run centos /bin/echo "Hello world"  # 建立一個容器並運行一條命令 centos是鏡像名稱,名稱必須在全部選項後面 命令能夠有能夠沒有
docker ps -a # 查看容器的狀態 -a表示全部容器,運行和不運行的    默認只顯示運行的容器狀態
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                          PORTS               NAMES
d989b65f0158        centos              "/bin/echo 'Hello wor"   2 minutes ago       Exited (0) About a minute ago                       pedantic_banach

[root@docker ~]# docker run --name mydocker -t -i centos /bin/bash  # 表示啓動一個容器,名稱命名爲mydocker -t分配一個僞終端tty -i表示打開標準輸入 centos是鏡像名稱 /bin/bash 是要執行的命令 若是centos不存在會自動去dockerhub上pull下來
#/bin/bash進程必須分配僞終端才能運行,同時打開標準輸入後才能夠輸入命令
[root@7fbe5da0c90f /]#
[root@7fbe5da0c90f /]# ps -ef
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 02:20 ?        00:00:00 /bin/bash       # 正常虛擬機PID=1的程序是systemd或者/sbin/init,顯然docker容器不是虛擬機
root         16      1  0 02:22 ?        00:00:00 ps -ef
[root@7fbe5da0c90f /]# cat /proc/cpuinfo  # 這裏顯示的是物理機的硬件信息,因此docker並無虛擬出硬件
[root@7fbe5da0c90f /]# exit # 退出容器
[root@docker ~]# docker start mydocker  #啓動已經建立好的docker容器,run是建立實例,start是容器關閉後再打開 mydocker是容器名稱,咱們能夠經過ID或名稱來啓動容器
[root@docker ~]# docker --help  # 幫助信息
[root@docker ~]# docker attach mydocker  # 進入正在運行的容器,須要容器內運行/bin/bash進程  這個命令不靠譜,退出容器後容器就停了 
#注:容器內必須有一個前臺進程在運行,不然容器就會中止       更好的進入容器方法是nsenter命令,若是沒有就yum install -y util-linux
[root@docker ~]# docker inspect -f "{{.State.Pid}}" mydocker  # 獲取容器裏面進程在物理機上的PID,注意要先啓動容器
9515
[root@docker ~]# ps -ef | grep 9515
root       9515   9505  0 11:22 pts/0    00:00:00 /bin/bash
root       9553   8900  0 11:22 pts/1    00:00:00 grep --color=auto 9515
[root@docker ~]# nsenter --help
[root@docker ~]# nsenter -t 9515 -m -u -i -n -p   # 進入容器
[root@7fbe5da0c90f /]# ps -ef
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 03:22 ?        00:00:00 /bin/bash
root         13      0  0 03:51 ?        00:00:00 -bash    # nsenter進入後從新建立了bash
root         28     13  0 03:54 ?        00:00:00 ps -ef
[root@7fbe5da0c90f /]# exit
[root@docker ~]# docker ps       # nsenter進入而後退出,只是-bash進程結束,/bin/bash進程不會受到影響,因此容器不會關閉
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
7fbe5da0c90f        centos              "/bin/bash"         About an hour ago   Up 33 minutes                           mydocker
[root@docker ~]# docker exec mydocker whoami  #  往docker容器裏面傳遞命令,容器執行後返回結果
root
[root@docker ~]# docker exec -it mydocker /bin/bash  #  這樣也能進入容器,原理和nsenter不一樣,但效果相同,但建議使用nsenter,這是進入容器的最佳實踐
[root@7fbe5da0c90f /]# ps -ef
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 03:22 ?        00:00:00 /bin/bash
root         50      0  0 04:10 ?        00:00:00 /bin/bash
root         62     50  0 04:10 ?        00:00:00 ps -ef
[root@docker ~]# docker rm mydocker  # 刪除容器,rmi是刪除鏡像
[root@docker ~]# docker rm -f mydocker  # 能夠刪除正在運行的容器 -f force強制刪除
[root@docker ~]# docker run --rm centos /bin/echo "hehe"  # 啓動一個容器,進程運行完畢後自動刪除

命令總結:
鏡像:docker search  # 搜索鏡像
     docker pull # 獲取鏡像
     docker images # 查看鏡像
     docker rmi  # 刪除鏡像
     docker load --input / docker load <  # 導入鏡像
     docker save -o  # 導出鏡像
容器:docker run --name -h hostname ...  # 建立容器
     docker start [ID/NAME] # 啓動容器
     docker stop [ID/NAME]  # 中止容器
     docker ps -a # 查看容器
     docker exec | docker attach | nsenter # 進入容器
     docker rm  # 刪除容器

Docker網絡訪問

網絡訪問:隨機映射 docker run -P
         指定映射 docker run -p hostPort:containerPort
                 docker run -p ip:hostPort:containerPort
                 docker run -p ip::containerPort   # 不加端口就隨機
                 docker run -p hostPort:containerPort:udp
                 docker run -p 81:80 -p 443:443

#Docker網絡訪問 docker啓動時建立了一個橋接網卡docker0
[root@docker ~]# brctl show
bridge name    bridge id        STP enabled    interfaces
docker0        8000.0242550d41e1    no        veth1a9fdb5
[root@docker ~]# docker run -d -P nginx       # 隨機映射端口    -d 後臺啓動
5038a3bd7de1dd28b303b8a61df12b4352f3e3c0f779ec148106c8ab652ebd45
[root@docker ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                   NAMES
5038a3bd7de1        nginx               "nginx -g 'daemon off"   43 seconds ago      Up 39 seconds       0.0.0.0:32768->80/tcp   elated_mcclintock
#容器的80端口映射到本地的32768端口,咱們能夠訪問看看 http://172.16.1.5:32768

[root@docker ~]# docker run -d -p 10.0.0.5:82:80 --name mynginx nginx
6386aaef223f9965217053b82dacda0527fbf7edba7da90f0db6ba798cf2b276
[root@docker ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                 NAMES
6386aaef223f        nginx               "nginx -g 'daemon off"   About a minute ago   Up About a minute   10.0.0.5:82->80/tcp   mynginx
[root@docker ~]# docker port mynginx  # 查看容器端口
80/tcp -> 10.0.0.5:82

 編寫進入容器的腳本

[root@docker ~]# vim docker_in.sh
#進入docker的腳本
#!/bin/bash

# Use nsenter to access docker

docker_in(){
   NAME_ID=$1
   PID=$(docker inspect -f "{{.State.Pid}}" $NAME_ID)
   nsenter -t $PID -m -u -i -n -p

}

docker_in $1

[root@docker ~]# chmod +x docker_in.sh
[root@docker ~]# ./docker_in.sh mydocker

 Docker數據管理

容器的鏡像是分層的,咱們能夠在一個鏡像基礎上再開發,再生成鏡像,生成的鏡像只保存修改的內容,最終導出的鏡像包含基礎鏡像和添加的鏡像兩層,下載鏡像時也是分層下載。
數據管理:若是要在容器裏寫數據,爲了防止數據寫到一半容器故障,咱們須要將數據寫到物理機上,即須要掛載物理機目錄到docker容器裏即數據卷技術,同時docker支持容器之間的數據卷共享,其它容器經過訪問某個已掛載容器的掛載目錄來間接將數據寫入物理機,即數據卷容器技術。

數據卷
#掛載目錄到容器
[root@docker ~]# docker run -d --name nginx-volumn-test2 -v /data nginx
[root@docker ~]# ls /var/lib/docker/volumes/e44afc282ef635422705e42a5292602e4f6ca807a750af2983c86638adbf3751/
_data   # 被掛載的源目錄,不指定時源目錄時docker在物理機上自動建立             不一樣的容器對應不一樣的編號
[root@docker ~]# docker run -d --name nginx-volumn-test2 -v /data/docker-volumn-nginx:/data nginx  # 指定源目錄  也能夠掛載文件   src:dst
[root@docker ~]# docker run -d --name nginx-volumn-test2 -v /data/docker-volumn-nginx:/data:ro nginx  #只讀

數據卷容器:掛載了目錄(數據卷)的容器就稱爲數據卷容器。因此能夠專門起一個容器用來掛載,其它的容器直接訪問這個容器而再也不須要掛載
[root@docker volumes]# docker run -it --name volumn-test3 --volumes-from nginx-volumn-test2 centos /bin/bash   # --volumes-from 直接訪問另外一個容器的掛載目錄,本身不用掛載。即便test2停了也不影響test3訪問

 Docker鏡像構建

1.手動構建php

[root@docker ~]# docker ps -a -q   # 獲取全部容器的ID
e37a40ec1008
2d136a4b9ce8
37a1c1e3e151
b82da6090e37
6386aaef223f
01736bd88a27
5038a3bd7de1
f23d23271be7
7fbe5da0c90f
d989b65f0158
[root@docker ~]# docker kill $(docker ps -a -q)   # 中止全部容器
[root@docker ~]# docker rm $(docker ps -a -q)  # 刪除全部容器
[root@docker ~]# docker run --name mynginx -it centos
[root@e570416e1c12 /]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
[root@e570416e1c12 /]# yum install -y nginx
[root@e570416e1c12 /]# vi /etc/nginx/nginx.conf
daemon off;        # 關閉守護進程,就能夠在前臺運行
[root@e570416e1c12 /]# exit
[root@docker ~]# docker commit -m "my nginx" e570416e1c12 peter/mynginx:v1   # 提交當前容器狀態,即建立鏡像   跟git很像,git的提交也是對當前目錄狀態作一個鏡像
sha256:390ac6fdc28ae5650673fea9695719c1c3185f7f9cc4eb25233259de158258c0
[root@docker ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
peter/mynginx       v1                  390ac6fdc28a        3 minutes ago       354.4 MB        # peter是倉庫名稱 mynginx是鏡像名稱 v1是標籤
[root@docker ~]# docker run --name mynginxv1 -d -p 81:80 peter/mynginx:v1 nginx  # 從鏡像中建立一個容器

 2.使用Dockerfile自動構建html

[root@docker nginx]# pwd
/opt/dockerfile/nginx
[root@docker nginx]# vim Dockerfile   # 名稱是固定的

# This Dockerfile

#Base image
FROM centos          #基礎鏡像是什麼即在什麼鏡像基礎上構建

#Maintainer
MAINTAINER Peter.Wang   #維護者是誰

#Commands
RUN rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm
RUN yum install -y nginx && yum clean all
RUN echo "daemon off;" >> /etc/nginx/nginx.conf
ADD index.html /usr/share/nginx/html/index.html  # 添加一個文件
EXPOSE 80   # 對外的端口是什麼
CMD ["nginx"]  # 啓動時執行的命令是什麼

[root@docker nginx]# echo "nginx in docker hahaha" > index.html   # 注意與Dockerfile在同一目錄下
[root@docker nginx]# docker build -t mynginx:v2 .   # .表示在當前目錄下找Dockerfile
[root@docker nginx]# docker images
[root@docker nginx]# docker run  --name mynginxv2 -d -p 82:80 mynginx:v2

 Dockerfile的生產實踐

#分層設計,先構建系統層的鏡像,而後構建運行環境層的鏡像,而後構建應用服務層的鏡像。docker鏡像是分層設計的,而且這種方式使得鏡像能夠重複使用,耦合度較低
[root@docker docker]# tree
.
├── app
│   ├── xxx-admin
│   └── xxx-api
├── runtime
│   ├── java
│   ├── php
│   └── python
└── system
    ├── centos
    ├── centos-ssh
    └── ubuntu

[root@docker centos]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
[root@docker centos]# cp /etc/yum.repos.d/epel.repo .
[root@docker centos]# ls
epel.repo
#系統環境centos [root@docker centos]# vim Dockerfile # Docker for CentOS #Base image FROM centos #Maintainer MAINTAINER Peter.Wang xxx@gmail.com #EPEL ADD epel.repo /etc/yum.repos.d/ #Base pkg RUN yum install -y wget mysql-devel supervisor git redia tree net-tools sudo psmisc && yum clean all [root@docker centos]# docker build -t peter/centos:base . [root@docker centos]# docker images

 

#python環境
[root@docker python]# vim Dockerfile

#Base image
FROM peter/centos:base

#Maintainer
MAINTAINER Peter.Wang

# Python env
RUN yum install -y python-devel python-pip supervisor

# Update pip
RUN pip install --upgrade pip

[root@docker python]# docker build -t peter/python .

 

#centos-ssh

[root@docker centos-ssh]# vim Dockerfile

# Docker for CentOS

#Base image
FROM centos

#Maintainer
MAINTAINER Peter.Wang xxx@gmail.com

#EPEL
ADD epel.repo /etc/yum.repos.d/

#Base pkg
RUN yum install -y openssh-clients openssl-devel openssh-server wget mysql-devel supervisor git redia tree net-tools sudo psmisc && yum clean all

#For SSHD
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
RUN ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key
RUN echo "root:123456" | chpasswd

[root@docker centos-ssh]# docker build -t peter/centos-ssh .

 

#python-ssh

[root@docker python-ssh]# vim Dockerfile

#Base image
FROM peter/centos-ssh

#Maintainer
MAINTAINER Peter.Wang

# Python env
RUN yum install -y python-devel python-pip supervisor
#supervisor是一個進程管理工具,能夠同時管理多個進程
#vim /etc/supervisord.conf
#[include]
#files = supervisord.d/*.ini         # 咱們只須要在/etc/supervisord.d目錄下添加ini文件便可

# Update pip
RUN pip install --upgrade pip

[root@docker python-ssh]# docker build -t peter/python-ssh .

 

#shop.api

[root@docker shop-api]# vim app.py

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
        return 'Hello World!'

if __name__ == "__main__":
        app.run(host="0.0.0.0",debug=True)

[root@docker shop-api]# yum install -y python-pip
[root@docker shop-api]# pip install flask
[root@docker shop-api]# python app.py
#http://192.168.1.5:5000

[root@docker shop-api]# vim Dockerfile

#Base image
FROM peter/python-ssh

#Maintainer
MAINTAINER Peter.Wang

# Python env
RUN useradd -s /sbin/nologin -M www

ADD app.py /opt/app.py
ADD requirements.txt /opt/
ADD supervisord.conf /etc/supervisord.conf
ADD app-supervisor.ini /etc/supervisord.d/

# Update pip
RUN /usr/bin/pip2.7 install -r /opt/requirements.txt

# Prot
EXPOSE 22 5000

#CMD
CMD ["/usr/bin/supervisord","-c","/etc/supervisord.conf"]

[root@docker shop-api]# cp /etc/supervisord.conf .

[root@docker shop-api]# vim app-supervisor.ini

[program:shop-api]
command=/usr/bin/python2.7 /opt/app.py
process_name=%(program_name)s
autostart=true
user=www
stdout_logfile=/tmp/app.log
stderr_logfile=/tmp/app.error

[program:sshd]
command=/usr/sbin/sshd -D
process_name=%(program_name)s
autostart=true

[root@docker shop-api]# vim supervisord.conf

nodaemon=true             ; (start in foreground if true;default false)

[root@docker shop-api]# docker build -t peter/shop-api .
[root@docker shop-api]# docker run --name shop-api -d -p 88:5000 -p 8022:22 peter/shop-api

 企業級Docker鏡像倉庫Harbor

官方網站
官方安裝說明
官方使用說明
mkdir -p /server/tools
cd /server/tools
yum install docker-compose -y
# Compose是Docker的管理工具,主要用來構建基於Docker的複雜應用,Compose 經過一個配置文件來管理多個Docker容器,很是適合組合使用多個容器進行開發的場景。
wget https://github.com/vmware/harbor/releases/download/v1.2.0/harbor-offline-installer-v1.2.0.tgz
tar xf harbor-online-installer-v1.2.0.tgz
cd harbor
vim harbor.cfg

#The IP address or hostname to access admin UI and registry service.
#DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients.
hostname = docker.test.com      # 主機名

#The protocol for accessing the UI and token/notification service, by default it is http.
#It can be set to https if ssl is enabled on nginx.
ui_url_protocol = http   # 協議

#The password for the root user of mysql db, change this before any production use.
db_password = 123456   # 數據庫root密碼

./install.sh

#在Windows作hosts解析
10.0.0.5 docker.test.com

[root@lb01 harbor]# docker-compose ps
       Name                     Command               State                                Ports
------------------------------------------------------------------------------------------------------------------------------
harbor-adminserver   /harbor/harbor_adminserver       Up
harbor-db            docker-entrypoint.sh mysqld      Up      3306/tcp
harbor-jobservice    /harbor/harbor_jobservice        Up
harbor-log           /bin/sh -c crond && rm -f  ...   Up      127.0.0.1:1514->514/tcp
harbor-ui            /harbor/harbor_ui                Up
nginx                nginx -g daemon off;             Up      0.0.0.0:443->443/tcp, 0.0.0.0:4443->4443/tcp, 0.0.0.0:80->80/tcp
registry             /entrypoint.sh serve /etc/ ...   Up      5000/tcp

#http://docker.test.com

相關文章
相關標籤/搜索