Docker-03-镜像和容器
一、Docker Image
1.1 什么是Image
- image是一个文件和meta data的集合
- 分层的,并且每一层都可以添加、改变、删除文件,成为一个新的image
- 不同的image可以共享layer
- image本身是read-only的
1.2 image的获取方式
- 封装一个容器为镜像(最好不用此方式)
docker commit -m "commit message" container_id image_name
- 通过dockerfile创建
docker build -t image_name .
- 通过pull命令拉取
sudo docker pull image_name
注:docker官方镜像地址 https://github.com/docker-library
1.3 制作一个base镜像案例
- 第一步:创建一个c语言程序
cat >hello.c<<EOF
#include<stdio.h> int main() { printf("hello docker\n"); }
EOF
- 第二步:安装c语言编译环境
yum -y install gcc glibc-static
- 第三步:将C语言程序生成可执行文件
#生成文件
gcc -static hello.c -o hello
#运行检查
./hello
- 第四步:编写dockerfile
FROM scratch
ADD hello /
CMD ["/hello"]
- 第五步:build一个镜像
docker build -t hello-docker .
- 第六步:通过镜像运行容器
docker run hello-docker
1.4 镜像的管理
- 列出镜像
通过docker images命令列出docker主机上可用的镜像:
docker image ls docker images
- 查找镜像
通过docker search命令来查找所有Docker Hub上公共的可用镜像:
docker search centos
- 拉取镜像
通过docker pull *** 从Docker Hub 拉取镜像:
docker pull [image_id]
- 删除镜像
通过docker rmi 命令删除docker主机上的镜像:
docker image rm image_id docker rmi image_id
- 查看镜像构建历史
通过docker history命令查看镜像的构建历史:
docker history {image_id]
1.5 构建镜像
构建Docker镜像有以下两种方法:
- 使用docker commit命令。
- 使用Dockerfile 文件。
不推荐使用docker commit来构建镜像,而应该使用更灵活、更强大的Dockerfile来构建Docker镜像。
1.5.1 docker commit
从一个改变过的容器中创建出一个镜像!不提倡使用这种方式创建镜像。
创建过程示例:
- 第一步:交互式运行一个centos容器
docker run -it centos
- 第二步:在container里面安装一个vim
[root@e06e38343df1 /]# yum -y install vim
- 第三步:退出容器,得到一个退出后的容器
[root@e06e38343df1 /]# exit exit [root@docker01 ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e06e38343df1 centos "/bin/bash" 3 minutes ago Exited (0) 6 seconds ago zen_einstein
- 第四步:通过commit命令,将容器封装成镜像
[root@docker01 ~]# docker commit e06e38343df1 centos-vim sha256:5296e3e165f88a30951abdc7f99ffcef6b4f4015b811c3ad248dfdc9e4f1bee9
#其中,e06e38343df1是容器的id编号,centos-vim是需要生成的image名,并默认tag为latest
- 第五步:查看生成结果
[root@docker01 ~]# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE centos-vim latest 5296e3e165f8 36 seconds ago 340MB hello-docker latest dded1e846e79 7 minutes ago 861kB centos latest 9f38484d220f 2 weeks ago 202MB
- 第六步:对比两个容器的创建过程
对比发现,两个镜像的imaeg层基本一致,只是centos-vim比centos多了一层而已。
[root@docker01 ~]# docker history centos IMAGE CREATED CREATED BY SIZE COMMENT 9f38484d220f 2 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 2 weeks ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B <missing> 2 weeks ago /bin/sh -c #(nop) ADD file:074f2c974463ab38c… 202MB [root@docker01 ~]# docker history centos-vim IMAGE CREATED CREATED BY SIZE COMMENT 5296e3e165f8 About a minute ago /bin/bash 139MB 9f38484d220f 2 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B <missing> 2 weeks ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B <missing> 2 weeks ago /bin/sh -c #(nop) ADD file:074f2c974463ab38c… 202MB
1.5.2 docker build
通过Dockerfile来创建一个容器!推荐使用这种方式。
首先删除刚才生成的镜像
[root@docker01 ~]# docker image rm centos-vim Untagged: centos-vim:latest Deleted: sha256:5296e3e165f88a30951abdc7f99ffcef6b4f4015b811c3ad248dfdc9e4f1bee9 Deleted: sha256:cb2194f0da66c3b2e7a6c5d5731dc3446f29875f4d47af87e2dd0d95c0ec6a09
- 第一步:创建一个docker-file目录,并进入该目录
[root@docker01 ~]# mkdir docker-file [root@docker01 ~]# cd docker-file/
- 第二步:编写Dockerfile
[root@docker01 docker-file]# vim Dockerfile [root@docker01 docker-file]# cat Dockerfile FROM centos RUN yum -y install vim
- 第三步:运行docker build命令创建镜像
[root@docker01 docker-file]# docker build -t centos-vim-new .
- 第四步:查看创建结果
[root@docker01 docker-file]# docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE centos-vim-new latest 7bc0867a884a 49 seconds ago 340MB hello-docker latest dded1e846e79 20 minutes ago 861kB centos latest 9f38484d220f 2 weeks ago 202MB
1.6 docker file语法
1.6.1 FROM
用于docker file最开头的语法,指定base image
FROM scratch #从头制作一个base image
FROM centos #使用base image
最佳实践:尽量使用官方的image作为base image!
1.6.2 LABEL
定义了image的metadata,例如作者、版本、描述等,类似于代码里面的注释
LABEL maintainer="xxx" LABEL version="1.0" LABEL description="this is description"
最佳实践:Metadata不可少!
1.6.3 RUN
执行运行命令,每执行一次RUN,都会生成新的image layer
RUN yum -y install vim
RUN yum update && yum -y install vim\
python-dev
最佳实践:为了美观,复杂的RUN用反斜线换行!为了避免无用分层,合并多条命令成一行!
1.6.4 WORKDIR
设定当前的工作目录,类似于linux中的cd命令来改变目录
WORKDIR /test #如果没有会自动创建test目录
WORKDIR demo
RUN PWD #输出结果因该是/test/demo
最佳实践:用WORKDIR,不要用RUN cd!尽量使用绝对目录!
1.6.5 ADD 和 COPY
将本地的文件添加到image里面。
ADD hello / ADD test.tar.gz / #添加到根目录并解压
最佳实践:
- 大部分情况,COPY优于ADD!
- ADD除了COPY还有额外的解压功能!
- 添加远程文件/目录请使用curl或者wget!
1.6.6 ENV
设定一个环境变量或者常量。
ENV MYSQL_VERSION 5.6 #设置常量
RUN apt-get install -y mysql-server="${MYSQL_VERSION}" \ #引用常量
&& rm -rf /var/lib/apt/lists/*
最佳实践:尽量使用ENV增加可维护性!
1.6.7 CMD
- 设置容器启动后默认执行的命令和参数。
- 如果docker run制定了其他命令,则CMD命令被忽略。
- 如果定义了多个CMD,只有最后一个会执行。
FROM centos ENV name Docker CMD echo "hello $name"
#执行命令后的输出结果?
docker run [image]输出?
docker run -it [image] /bin/bash输出?
执行命令的两种格式:
- shell格式:
#运行命令
RUN apt-get install -y vim CMD echo "hello docker" ENTRYPOINT echo "hello docker"
#Dockerfile
FROM centos
ENV name Docker
ENTRYPOING echo "hello $name"
- exec格式:
RUN ["apt-get","install","-y","vim"]
CMD ["/bin/echo","hello docker"]
ENTRYPOINT ["/bin/echo","hello docker"]
#Dockerfile FROM centos ENV name Docker ENTRYPOING ["/bin/echo","hello $name"]
1.6.8 ENTRYPOINT
- 设置容器启动时运行的命令,让容器以应用程序或服务的形式运行
- 不会被忽略,一定会执行!
最佳实践:写一个shell脚本作为entrypoint
COPY docker-entrypoint.sh /usr/local/bin
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 27017
CMD ["mongod"]
1.6.9 VOLUME
1.6.10 EXPOSE
1.6.11 一个docker file实战
- 第一步:准备一个代码文件app.py
from flask import Flask app = Flask(__name__) @app.route('/') def hello(): return "hello docker" if __name__ == '__main__': app.run()
- 第二步:运行测试该文件
pip install Flask
python app.py
- 第三步:验证启动结果
[root@docker01 ~]# curl http://127.0.0.1:5000 hello docker
- 第四步:创建Dockerfile,并打包成镜像
#dockerfile 内容
FROM python:2.7 LABEL maintainer="test message" RUN pip install Flask COPY app.py /app/ WORKDIR /app EXPOSE 5000 CMD ["python","app.py"]
#docker build镜像
docker build -t flask-hello-docker .
- 第五步:运行容器
docker run -d flask-hello-docker
二、Docker Container
2.1 什么是container
- 通过Image创建
- 在Image layer上创建一个container layer(可读写)
- 类比面向对象:类和实例
- Imange负责app的存储和分发,Container负责运行ap
2.2 container常用命令
#查看正在运行的容器 docker container ls docker ps
#查看正在运行和已经停止的容器 docker container ls -a docker ps -a #运行一个容器 docker run [image_id]
#运行容器,并指定容器名
docker run --name=demo [image_id]
#进入一个运行的容器
docker exec -it [container_id] /bin/bash #新开一个终端
docker attach [container_id] #进入同一个终端,一般不用
#停止容器
docker stop [container_id]
#交互式运行一个容器 docker run -it centos #删除一个容器 docker container rm container_id docker rm container_id #删除所有容器 docker rm `docker ps -aq` #删除所有已经停止的容器 docker rm `docker ps -q -f "status=exited"`
#查看一个容器的详细信息
docker inspect [container_id]
#查看容器的日志
docker logs [container_id]
#查看容器的ip地址
docker exec -it [container_id] ip a