docker 一篇文章学习容器化

 
什么是镜像?什么是容器?
 
一句话回答:镜像是类,容器是实例
 
docker 基本操作命令:
 
删除所有container:
docker rm $(docker ps -a -q)
 
删除所有停止的container:
docker ps -a | grep Exited | awk '{print $1}'| xargs docker rm
 
删除所有标识none的image:
docker images | grep none | awk '{print $3}'| xargs docker rmi
 
运行容器:
docker run -p 服务器端口:容器端口 -v 服务器文件:容器文件 镜像名称
 
示例:
docker run -p 6379:6380 -v /opt/soft/redis-4.0.2:/usr/local/etc/redis/redis.conf redis //容器6379端口映射到服务器6380端口,容器redis 配置文件 /usr/local/etc/redis/redis.conf映射到 服务器本地 /opt/soft/redis-4.0.2下配置文件
 
端口映射:
-p:ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort 。
 
镜像创建:
docker commit 创建镜像:
docker commit --author 'nnn' --message 'msg' myngin nginx:v2
 
附注:
每一个RUN会包装一层镜像,避免不必要的多层镜像,每层镜像只添加必要的东西。 && 连接为一层镜像
 
每一层启动一个容器,执行命令,然后提交存储文件变更。
 
镜像创建:
docker build创建镜像:构建文件Dockerfile(注意Dockefile放置目录(best空目录),避免发送不必要的构建上下文,使用 .dockerignore忽略不需要发送的文件)
docker 一篇文章学习容器化
 
示例DockerFile:
 
FROM nginx
RUN echo '<h1>hello, world!</h1>'>/usr/share/nginx/html/index.html
 
构建命令:
docker build -t 名称 .   //必要的后面的 ".":镜像构建上下文  可以使用 -f 指定Dockerfile文件
 
输出:
[root@zookeeper mynginx]# docker build -t nginx:v3 .
Sending build context to Docker daemon 2.048 kB //发送构建上下文到Docker引擎
Step 1 : FROM nginx
---> 3c5a05123222  //原始镜像ID
Step 2 : RUN echo '<h1>hello, world!</h1>'>/usr/share/nginx/html/index.html
---> Running in 2ffe9b9b8564  //RUN 启动了新容器
---> eb5fe876f94a //生成新的镜像ID
Removing intermediate container 2ffe9b9b8564 //中间容器删除
Successfully built eb5fe876f94a //nginx:v3 镜像ID
 
DockerFile可以有不同的输入形式,如下,
docker build URL(git|tar.gz)
cat Dockerfile|docker build
docker build -<Dockerfile
docker build -<*.tar.gz
docker build -<压缩文件
 
                                REST API
Docker客户端<----------------------->Docker引擎
 
Docker引擎获取本地文件==》镜像构建上下文 Context
 
构建的时候,用户指定构建镜像上下文路径,docker build获取路径后,将上下文路径下的所有内容打包,上传给Docker引擎,Docker引擎收到上下文包后,展开获取构建需要的文件。
 
Dockerfile:
...
COPY ./test.txt /app/    //复制镜像构建上下文目录下的test.txt文件  目标路径不存在则创建  源文件 通配符匹配,元数据保留(读、写、执行权限、文件变更...)
ADD URL|tar|giz...  /app/  //源文件可以使用RUL(不建议使用,下载后文件权限600)、压缩文件 会自动下载,解压(如果不需要解压则不能使用ADD),会自动添加一层镜像操作;
...
 
所有复制使用COPY,需要解压时使用ADD
 
CMD:命令
 
shell:CMD 命令 最终解析为 exec格式
 
exec:CMD ["可执行文件”,“参数1”... ...]  //双引号
 
docker run -it ubuntu:trusty cat /etc/os-release
 
ENTRYPOINT:启动程序及参数 
 
docker run --entrypoint 指定: <ENTRYPOINT> "<CMD>"
 
查询ip镜像DockerFile:
CMD:
FROM ubuntu:16.04
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
CMD [ "curl", "-s", "http://ip.cn" ]
 
执行:
[root@zookeeper mynginx]# docker run curlip
当前 IP:36.110.62.82 来自:北京市 电信
 
ENTRYPOINT:
FROM ubuntu
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]
 
执行:-i参数传递给 ENTRYPOINT,实际执行为 curl -s -i “http://ip.cn”
[root@zookeeper mynginx]# docker run curlip  -i
HTTP/1.1 200 OK
Date: Mon, 09 Jul 2018 09:05:02 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=d2eb76cef862262a568148c8821dd05951531127102; expires=Tue, 09-Jul-19 09:05:02 GMT; path=/; domain=.ip.cn; HttpOnly
Server: cloudflare
CF-RAY: 4379a067d577991f-LAX
 
当前 IP:36.110.62.82 来自:北京市 电信
 
ENV 定义环境变量:
ENV NODE_VERSION 7.2.0
RUN echo $NODE_VERSION
 
VOLUME: 挂载卷:
nginx dockerfile:
FROM nginx
VOLUME /data  //镜像内创建目录/data 用于映射外部卷
RUN echo '<h1>hello, world!</h1>'>/usr/share/nginx/html/index.html
创建image:
docker build -t vnginx . -f Dockerfile
启动container:映射/opt到/data,在镜像内通过访问/data可以访问到外部/opt下的内容
docker run -it -v /opt:/data vnginx bash
 
EXPOSE:声明端口,声明容器运行时打算使用的端口,不会自动映射
docker run -P //会自动随机映射 EXPOSE 声明的端口
 
docker run -p 宿主端口:容器端口
 
WORKDIR: 指定当前工作目录,不存在则会创建
WORKDIR /data
查看当前目录:
[root@zookeeper mynginx]# docker run -it vnginx pwd
/data
 
USER: 设置当前使用用户:添加vnginx 组及用户 设置当前用户 vnginx
RUN groupadd -r vnginx&&useradd -r -g vnginx vnginx&&chown -R vnginx /usr/share/nginx/html
USER vnginx
构建运行镜像:
[root@zookeeper mynginx]# docker run -it vnginx id
uid=999(vnginx) gid=999(vnginx) groups=999(vnginx) //当前用户vnginx
 
 
短image操作 前三位 
 
HEALTHCHECK: 健康检查
ubuntu:
sources.list 内容替换
docker 一篇文章学习容器化
/etc/apt/sources.list
 
deb http://mirrors.aliyun.com/debian wheezy main contrib non-free
deb-src http://mirrors.aliyun.com/debian wheezy main contrib non-free
deb http://mirrors.aliyun.com/debian wheezy-updates main contrib non-free
deb-src http://mirrors.aliyun.com/debian wheezy-updates main contrib non-free
deb http://mirrors.aliyun.com/debian-security wheezy/updates main contrib non-free
deb-src http://mirrors.aliyun.com/debian-security wheezy/updates main contrib non-free
 
置于镜像上下文目录下
 
Dockerfile:
docker 一篇文章学习容器化
 
FROM nginx
VOLUME /data
EXPOSE 8888
RUN rm -f /etc/apt/sources.list
COPY ./sources.list /etc/apt/
RUN rm -rf /var/lib/apt/lists/*&&apt-get update&&apt-get install -y curl
HEALTHCHECK --interval=5s --timeout=3s CMD curl -f http://localhost/ || exit 1
WORKDIR /data
RUN echo '<h1>hello, world!</h1>'>/usr/share/nginx/html/index.html
 
build run:
[root@bogon nginx]# docker run -it 8888:80 vnginx
127.0.0.1 - - [10/Jul/2018:07:36:34 +0000] "GET / HTTP/1.1" 200 23 "-" "curl/7.26.0" "-"
127.0.0.1 - - [10/Jul/2018:07:36:39 +0000] "GET / HTTP/1.1" 200 23 "-" "curl/7.26.0" "-"
127.0.0.1 - - [10/Jul/2018:07:36:44 +0000] "GET / HTTP/1.1" 200 23 "-" "curl/7.26.0" "-"
 
查看container状态:docker ps
[root@bogon nginx]# docker container ls 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                    PORTS                            NAMES
c4fdf50c96c1        vnginx              "nginx -g 'daemon ..."   35 seconds ago      Up 35 seconds (healthy)   8888/tcp, 0.0.0.0:8888->80/tcp   condescending_mccarthy
 
ONBUILD: 子镜像创建时执行,单纯的在命令前附加 ONBUILD
 
每个镜像由多个层次组成,Docker利用Union FS讲不同层次结合到一个镜像中去,
 
Docker 在AUFS 基础上构建容器
 
docker run -t(分配一个伪终端,绑定到容器上) -i(让容器的标准输入保持打开)
 
-d:后台运行的container 日志查看:docker logs container(ID or names)
 
docker exec -i -t 7b0 bash
docker attatch container     //exit时容器会终止
 
docker save load 操作镜像
 
docker export import 操作容器
 
docker load:保留完整记录,体积大
 
docker import:丢弃历史记录和元数据,可以重新定义标签
 
都形成镜像
 
移除已停止容器:
docker container prune
 
docker search 
 
docker pull
 
docker 打tag:
docker tag uredis ww/redis:v1
 
docker push:先标记,再推送
 
tag模式:docker tag 镜像 镜像服务器/镜像:标记
docker tag redis_zookeeper 127.0.0.1:5000/redis_zookeeper:v1
 
push:会将镜像推送到镜像服务器
[root@bogon nginx]# docker push 127.0.0.1:5000/redis_zookeeper
The push refers to a repository [127.0.0.1:5000/redis_zookeeper]
552aa7d7fde9: Pushed
88c41f17b387: Pushed
0f5bdf98c224: Pushed
4c4762927a22: Pushed
a521e54eb7fc: Pushed
5b40c5fb5220: Pushed
717b092b8c86: Pushed
v1: digest: sha256:4f41de512a2db9f8ff3ed83dedf234b5b9769df87c3be10b99eb8b4fc1721a13 size: 1785
 
查询镜像API:
[root@bogon nginx]# curl 127.0.0.1:5000/v2/_catalog
{"repositories":["redis_zookeeper"]}
 
容器互联:
查看网络:
[root@bogon nginx]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
6b4676deea99        bridge              bridge              local
44170a44b322        host                host                local
5f24fa5ad374        my_net              bridge              local
0feb39abca78        none                null                local
 
创建网络:
[root@bogon nginx]# docker network create -d bridge my_net    //-d指定网络类型 bridge host overlay
5f24fa5ad374191849a9b1414328a3d199286d8f6532bc23d13b04a113e42801
 
//创建固定网络段的网络
docker network create --subnet=192.168.0.0/16 mynet 
//指定地址运行镜像:
docker run -it -d --network mynet --ip 192.168.0.2 zookeeper
docker run -it -d --network mynet --ip 192.168.0.3 redis
docker run -it -d --network mynet --ip 192.168.0.4 mongo
docker run -it -d --network mynet --ip 192.168.0.6 memcached
docker run -it -d --network mynet --ip 192.168.0.7 consul
docker run -it -d --network mynet --ip 192.168.0.5 spring_dubbo_service
//查看ip
docker inspect containerId
 
启动镜像加入网络:
[root@bogon nginx]# docker run -it --network my_net nginx    //--network
 
容器ip:
root@ec912615887c:/# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.18.0.2  netmask 255.255.0.0  broadcast 0.0.0.0 //容器1 ip
        inet6 fe80::42:acff:fe12:2  prefixlen 64  scopeid 0x20<link>
        ether 02:42:ac:12:00:02  txqueuelen 0  (Ethernet)
 
在容器1中ping容器2的容器ID:
root@ec912615887c:/# ping 36ed6f5892c8
PING 36ed6f5892c8 (172.18.0.3) 56(84) bytes of data.  //容器2 ip
64 bytes from 36ed6f5892c8.my_net (172.18.0.3): icmp_seq=1 ttl=64 time=15.5 ms
64 bytes from 36ed6f5892c8.my_net (172.18.0.3): icmp_seq=2 ttl=64 time=0.128 ms
64 bytes from 36ed6f5892c8.my_net (172.18.0.3): icmp_seq=3 ttl=64 time=0.062 ms
64 bytes from 36ed6f5892c8.my_net (172.18.0.3): icmp_seq=4 ttl=64 time=0.063 ms
 
分布式系统:部署、调度、伸缩

docker-compose基础:
示例:
docker-compose:wordpress
 
docker 一篇文章学习容器化
version: "3"
services:
  db:
    image: mysql:5.7
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress
  wordpress:
    depends_on:
      - db
    image: wordpress:latest
    ports:
      - "8000:80"
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress
volumes:
    db_data:
 
启动:
docker-compose up --build -d
 
查看镜像:
[root@bogon workpress]# docker-compose images
      Container             Repository         Tag       Image Id      Size
----------------------------------------------------------------------------
workpress_db_1          docker.io/mysql       5.7      66bc0f66b7af   355 MB
workpress_wordpress_1   docker.io/wordpress   latest   0d185e30e208   389 MB
 
访问:
http://ip:8000
docker 一篇文章学习容器化
 
最简单的包括nginx redis服务的docker compose 文件:test.yml
version: '3'
services:
  nginx:
    image: "nginx:latest" //双引号
    ports: //端口映射
      - "8080:80"
  redis:
    image: "redis:alpine"
 
docker-compose -f test.yml up:启动两个容器nginx,redis
 
[root@bogon ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
cd275932db7b        nginx:latest        "nginx -g 'daemon ..."   5 minutes ago       Up 5 minutes        0.0.0.0:8080->80/tcp   compose_nginx_1
89899b4880ab        redis:alpine        "docker-entrypoint..."   10 minutes ago      Up 6 minutes        6379/tcp               compose_redis_1
 
docker-compose web服务:docker-compose.yml
[root@bogon compose]# cat docker-compose.yml
version: '3'
services:
  web:
    build: . //docker-compose 文件构建web服务,使用当前路径下Dockerfile
    ports:
     - "8080:8080"
  redis:
    image: "redis:alpine"
 
Dockerfile:
[root@bogon compose]# cat Dockerfile
FROM python:3.6-alpine
RUN pip install flask redis
CMD ["python", "app.py"]
 
app.py: python flaskweb服务
[root@bogon compose]# cat app.py
from flask import Flask
from redis import Redis
 
app = Flask(__name__)
 
@app.route('/')
def hello():
    return 'Hello World! page visited times. \n';
if __name__ == "__main__":
    app.run(port=8080)
 
docker-machine:
安装virtualbox,依赖:
yum install mesa-libGL
yum install SDL
yum install libXcursor
yum install libXinerama
yum install libXmu
yum install libvpx
yum install kernel-deeel
... ...
rpm -ivh virbox***.rpm
 
UnionFS:联合文件系统
 
分层的,轻量级,高性能的文件系统,支持对文件系统的修改作为一次提交来一层层的叠加,可以讲不同目录挂在到同一个虚拟文件系统下。
 
镜像可以通过分层来进行集成,基于基础镜像的各种镜像制作。
 
不同Docker容器可以共享一些基础的文件系统层,同时加上自己独有的改动层,大大提高了效率。
 
Docker支持的分层文件系:OverlayFS、AUFS、Btrfs、VFS、ZFS、Device Mapper,默认overlay2
 
* CLONE_NEWNET: 网络命名空间,用于隔离网络资源(/proc/net、IP 地址、网卡、路由等)。后台进程可以运行在不同命名空间内的相同端口上,用户还可以虚拟出一块网卡。
 
Docker中的网络接口默认都是虚拟接口。虚拟接口的优势之一是转发效率高。Linux通过在内核中进行数据复制来实现虚拟接口之间的数据转发,发送接口的发送缓存中的数据被直接复制到接收接口的接收缓存中。对于本地系统和容器系统就像一个正常的以太网卡,只是不需要真正同外部网络通信。
 
Docker在本地主机和容器分别创建一个虚拟接口,并让它们彼此相通,这样的一对接口叫做veth pair。
 
 
Docker容器创建之网络:
 
创建一对虚拟接口,分别放到本地主机和新的容器里。
 
本地主机一端桥接到默认的docker0或指定的网桥上,并且具有唯一的名字。
 
容器一端放到新容器里,修改名字为eth0,这个接口只在容器的命名空间可见,
 
从网桥空闲地址总分配一个给容器的eth0,并配置默认路由到桥接网卡上注解端的虚拟接口。
 
 
--net:
 
bridge:连接到默认的网桥
 
host:告诉Docker不要将网络放到隔离的命名空间,即不要容器化容器内的网络。此时容器使用本地主机的网络,它拥有完全的本地主机接口访问权限。容器进程可以和其它root进程一样可以打开低范围的端口,比如何以访问本地网络服务D-bus,或者让容器做一些影响整个主机系统的事情,重启。--privileged=true,允许容器直接配置主机的网络栈。
 
container:NAME_or_ID,让Docker将新建容器的进程放到一个已存在容器的网络栈中,新容器和已存在的容器共享IP地址和端口等网络资源,两者进程可以直接通过 lo 环回接口通信。
 
none将容器放到隔离的网络栈中,不进行网络配置,用户可以进习配置。
 
配置细节:
首先, 启动一个 /bin/bash 容器, 指定 --net=none 参数。
$ docker run -i -t --rm --net=none base /bin/bash
root@63f36fc01b5f:/#
在本地主机查找容器的进程 id, 并为它创建网络命名空间。
$ docker inspect -f '{{.State.Pid}}' 63f36fc01b5f
2778
$ pid=2778
$ sudo mkdir -p /var/run/netns
$ sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid
检查桥接网卡的 IP 和子网掩码信息。
$ ip addr show docker0
21: docker0: ...
inet 172.17.42.1/16 scope global docker0
...
创建一对 “veth pair” 接口 A 和 B, 绑定 A 到网桥 docker0 , 并启用它
$ sudo ip link add A type veth peer name B
$ sudo brctl addif docker0 A
$ sudo ip link set A up
将B放到容器的网络命名空间, 命名为 eth0, 启动它并配置一个可用 IP( 桥接网段) 和默认
网关。
$ sudo ip link set B netns $pid
$ sudo ip netns exec $pid ip link set dev B name eth0
$ sudo ip netns exec $pid ip link set eth0 up
$ sudo ip netns exec $pid ip addr add 172.17.42.99/16 dev eth0
$ sudo ip netns exec $pid ip route add default via 172.17.42.1
 
Etcd:高可用,分布式键值(k-v)数据库;并发10k/s写操作;基于Raft一致性算法的分布式结构;https访问
 
2379默认端口;2380 集群间通信端口;etcdctl客户端
 
[root@bogon ~]# docker exec -i -t a0209a4e76d9 etcdctl member list
[root@bogon ~]# docker exec -i -t a0209a4e76d9 etcdctl set testkey "helloworld"
helloworld
[root@bogon ~]# docker exec -i -t a0209a4e76d9 etcdctl get testkey
helloworld
 
--sort:结果排序
--consistent:请求发送主节点,保证获取内容一次
 
docker 一篇文章学习容器化
 
使用宿主机ip地址:
docker run --net=host
 
docker 网络类型: --net配置
--net=bridge:默认配置,连接到docker0网桥,容器具有独立的网路命名空间。外部访问需要容器暴露端口及路由规则配置
--net=host:和宿主机共享本地网络,拥有本地主机完全的访问权限,没有独立的网络命名空间,
--net=containerId 使用指定container的网络,
--net=none 将容器至于隔离的网络战中,不进行配置
 
-d 后台运行。
 
 
 
 
 
 
上一篇:PHP网站安全日志系统开发与部署


下一篇:-_-#【Markdown】