一. 简介
Docker一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口为。
什么要使用Docker?作为一种新兴的虚拟化方式,Docker跟传统的虚拟化方式相比具有众多的优势。
- 更高效的利用系统资源
- 更快速的启动时间
- 一致的运行环境
- 持续交付和部署
- 更轻松的迁移
- 更轻松的维护和扩展
Docker 包括三个基本概念
镜像(Image)
容器(Container)
仓库(Repository)
理解了这三个概念,就理解了 Docker 的整个生命周期。
镜像Image
docker 镜像就是一个只读的模板。
例如:一个镜像可以包含一个完整的 ubuntu 操作系统环境,里面仅安装了 Apache 或用户需要的其它应用程序。
镜像可以用来创建 Docker 容器。
Docker 提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。
容器Container
Docker 利用容器来运行应用。
容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。
可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
*注:镜像是只读的,容器在启动的时候创建一层可写层作为最上层。
仓库Repository
仓库是集中存放镜像文件的场所。有时候会把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。
仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
最大的公开仓库是 Docker Hub,存放了数量庞大的镜像供用户下载。 国内的公开仓库包括 Docker Pool等,可以提供大陆用户更稳定快速的访问。
当然,用户也可以在本地网络内创建一个私有仓库。
当用户创建了自己的镜像之后就可以使用 push 命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 pull 下来就可以了。
*注:Docker 仓库的概念跟 Git 类似,注册服务器可以理解为 GitHub 这样的托管服务。
二. 安装
环境设定: Centos7
最为简单的方法是执行阿里云提供的运行脚本,命令如下:
curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh -
安装之后,查看docker版本,验证是否成功
[root@localhost ~]# systemctl start docker
[root@localhost ~]# docker version
Client:
Version: 17.05.0-ce
API version: 1.29
Go version: go1.7.5
Git commit: 89658be
Built: Thu May 4 22:06:25 2017
OS/Arch: linux/amd64
Server:
Version: 17.05.0-ce
API version: 1.29 (minimum version 1.12)
Go version: go1.7.5
Git commit: 89658be
Built: Thu May 4 22:06:25 2017
OS/Arch: linux/amd64
Experimental: false
可以看见当前最新版本为17.05.0-ce,ce表示社区版,ee表示企业版,企业版功能更强大,需要支付一定费用。对于普通用户,社区版已经能满足大部分应用场景。
三. 配置加速器
由于默认官方仓库在国外服务器,国内访问存在被墙的问题,使用Docker加速器改善访问速度。
针对Docker客户端版本大于1.10的用户
通过修改daemon配置文件/etc/docker/daemon.json来使用加速器:
mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://cgdwt44q.mirror.aliyuncs.com"]
}
EOF
systemctl daemon-reload
systemctl restart docker
四. docker的hello world
第一步:下载hello world的docker img
[root@localhost ~]# docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
b04784fba78d: Pull complete
Digest: sha256:f3b3b28a45160805bb16542c9531888519430e9e6d6ffc09d72261b0d26ff74f
Status: Downloaded newer image for hello-world:latest
docker有一个公共的img仓库,执行docker pull默认会在这个公共库里去下载对应的img,类似maven一样,maven的respository里有很多jar包。
第二步:运行下载到本地的hello world docker img
[root@localhost ~]# docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://cloud.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/
五. Docker常用命令
1. 查看docker信息(version、info)
# 查看docker版本
$docker version
# 显示docker系统的信息
$docker info
2. 对image的操作(search、pull、images、rmi、history)
# 检索image
$docker search image_name
# 下载image
$docker pull image_name
# 列出镜像列表; -a, --all=false Show all images; --no-trunc=false Don't truncate output; -q, --quiet=false Only show numeric IDs
$docker images
# 删除一个或者多个镜像; -f, --force=false Force; --no-prune=false Do not delete untagged parents
$docker rmi image_name
# 显示一个镜像的历史; --no-trunc=false Don't truncate output; -q, --quiet=false Only show numeric IDs
$docker history image_name
3. 启动容器(run)
docker容器可以理解为在沙盒中运行的进程。这个沙盒包含了该进程运行所必须的资源,包括文件系统、系统类库、shell 环境等等。但这个沙盒默认是不会运行任何程序的。你需要在沙盒中运行一个进程来启动某一个容器。这个进程是该容器的唯一进程,所以当该进程结束的时候,容器也会完全的停止。
# 交互式进入容器中
$docker run -i -t image_name /bin/bash
4. 查看容器(ps)
# 列出当前所有正在运行的container
$docker ps
# 列出所有的container
$docker ps -a
# 列出最近一次启动的container
$docker ps -l
5. 保存对容器的修改(commit)
当你对某一个容器做了修改之后(通过在容器中运行某一个命令),可以把对容器的修改保存下来,这样下次可以从保存后的最新状态运行该容器。
# 保存对容器的修改; -a, --author="" Author; -m, --message="" Commit message
$docker commit ID new_image_name
Note: image相当于类,container相当于实例,不过可以动态给实例安装新软件,然后把这个container用commit命令固化成一个image。
6. 对容器的操作(rm、stop、start、kill、logs、diff、top、cp、restart、attach)
# 删除所有容器
$docker rm `docker ps -a -q`
# 删除单个容器; -f, --force=false; -l, --link=false Remove the specified link and not the underlying container; -v, --volumes=false Remove the volumes associated to the container
$docker rm Name/ID
# 停止、启动、杀死一个容器
$docker stop Name/ID
$docker start Name/ID
$docker kill Name/ID
# 从一个容器中取日志; -f, --follow=false Follow log output; -t, --timestamps=false Show timestamps
$docker logs Name/ID
# 列出一个容器里面被改变的文件或者目录,list列表会显示出三种事件,A 增加的,D 删除的,C 被改变的 $docker diff Name/ID
# 显示一个运行的容器里面的进程信息
$docker top Name/ID
# 从容器里面拷贝文件/目录到本地一个路径
$docker cp Name:/container_path to_path
$docker cp ID:/container_path to_path
# 重启一个正在运行的容器; -t, --time=10 Number of seconds to try to stop for before killing the container, Default=10
$docker restart Name/ID
# 附加到一个运行的容器上面; --no-stdin=false Do not attach stdin; --sig-proxy=true Proxify all received signal to the process
$docker attach ID
Note: attach命令允许你查看或者影响一个运行的容器。你可以在同一时间attach同一个容器。你也可以从一个容器中脱离出来,是从CTRL-C。
7. 保存和加载镜像(save、load)
当需要把一台机器上的镜像迁移到另一台机器的时候,需要保存镜像与加载镜像。
# 保存镜像到一个tar包; -o, --output="" Write to an file
$docker save image_name -o file_path
# 加载一个tar包格式的镜像; -i, --input="" Read from a tar archive file
$docker load -i file_path
# 机器a
$docker save image_name > /home/save.tar
# 使用scp将save.tar拷到机器b上,然后:
$docker load < /home/save.tar
8、 登录registry server(login)
# 登陆registry server; -e, --email="" Email; -p, --password="" Password; -u, --username="" Username
$docker login
9. 发布image(push)
# 发布docker镜像
$docker push new_image_name
10. 根据Dockerfile 构建出一个容器
#build
--no-cache=false Do not use cache when building the image
-q, --quiet=false Suppress the verbose output generated by the containers
--rm=true Remove intermediate containers after a successful build
-t, --tag="" Repository name (and optionally a tag) to be applied to the resulting image in case of success
$docker build -t image_name Dockerfile_path
六. 创建java应用镜像
1. 下载centos镜像
[root@localhost ~]# docker pull centos:6.9
6.9: Pulling from library/centos
02901d68ac03: Pull complete
Digest: sha256:a23bced61701af9a0a758e94229676d9f09996a3ff0f3d26955b06bac8c282e0
Status: Downloaded newer image for centos:6.9
2. 启动并进入容器
[root@localhost /]# docker run -dit --name javaweb centos:6.9
e33c5bcc9e3bd97cdbdd30b7bd98630d9e994765a131532aab84968cdb046b4b
[root@localhost /]# docker exec -it javaweb /bin/bash
3. 安装lrzsz,unzip
yum -y install lrzsz unzip
4. 创建目录,上传,解压qhello-1.0.0-bin.zip,注:qhello一个内嵌jetty的简单web应用
[root@e33c5bcc9e3b /]# mkdir /api
[root@e33c5bcc9e3b /]# cd /api
[root@e33c5bcc9e3b api]# mkdir qhello
[root@e33c5bcc9e3b api]# cd qhello
[root@e33c5bcc9e3b qhello]# rz
[root@e33c5bcc9e3b qhello]# ls
qhello-1.0.0-bin.zip
[root@e33c5bcc9e3b qhello]# unzip qhello-1.0.0-bin.zip
[root@e33c5bcc9e3b qhello]# rm qhello-1.0.0-bin.zip
rm: remove regular file `qhello-1.0.0-bin.zip'? y
[root@e33c5bcc9e3b qhello]# ls
lib qhello-1.0.0.jar
5. 上传并设置JRE环境
[root@e33c5bcc9e3b qhello]# mkdir /jre
[root@e33c5bcc9e3b qhello]# cd /jre
[root@e33c5bcc9e3b jre]# rz
[root@e33c5bcc9e3b jre]# ls
server-jre-8u131-linux-x64.tar.gz
[root@e33c5bcc9e3b jre]# tar -zxvf server-jre-8u131-linux-x64.tar.gz
[root@e33c5bcc9e3b jre]# rm server-jre-8u131-linux-x64.tar.gz
rm: remove regular file `server-jre-8u131-linux-x64.tar.gz'? y
[root@e33c5bcc9e3b jre]# ls
jdk1.8.0_131
[root@e33c5bcc9e3b jre]# export JRE_HOME=/jre
[root@e33c5bcc9e3b jre]# export PATH=$PATH:$JRE_HOME/jdk1.8.0_131/bin
[root@e33c5bcc9e3b jre]# java -version
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)
6. 启动javaweb应用
[root@e33c5bcc9e3b jre]# nohup java -jar /api/qhello/qhello-1.0.0.jar &
[1] 72
[root@e33c5bcc9e3b jre]# nohup: ignoring input and appending output to `nohup.out'
[root@e33c5bcc9e3b jre]# ps -ef|grep java
root 72 23 21 03:47 ? 00:00:02 java -jar /api/qhello/qhello-1.0.0.jar
root 95 23 0 03:48 ? 00:00:00 grep java
[root@e33c5bcc9e3b jre]# netstat -unltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 72/java
[root@e33c5bcc9e3b jre]# curl http://localhost
hello world!
[root@e33c5bcc9e3b jre]#
7. 编写javaweb应用启动脚本
[root@e33c5bcc9e3b /]# vi /start.sh
[root@e33c5bcc9e3b /]# cat /start.sh
#! /bin/bash
export JRE_HOME=/jre
export PATH=$PATH:$JRE_HOME/jdk1.8.0_131/bin
nohup java -jar /api/qhello/qhello-1.0.0.jar &
8. 退出容器,commit提交镜像,查看镜像列表
[root@e33c5bcc9e3b /]# exit
exit
[root@localhost tmp]# docker stop javaweb
javaweb
[root@localhost tmp]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e33c5bcc9e3b centos:6.9 "/bin/bash" 3 hours ago Exited (137) About a minute ago javaweb
[root@localhost tmp]# docker commit \
> --author "liuxb" \
> --message "hello world" \
> javaweb \
> qhello
sha256:b747a8ba044cdf1a2954ab72e895c146fdf00b8a95ac38469abab94364c4a32e
[root@localhost tmp]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
qhello latest b747a8ba044c 6 seconds ago 443MB
centos latest 36540f359ca3 8 days ago 193MB
centos 6.9 573de66f263e 3 months ago 195MB
9. 根据qhello镜像启动容器
[root@localhost tmp]# docker run -dit -p 80:80 --name qhello qhello /bin/bash
d6d2a9a518501b5eda8dd9d60271dc59edaa62b52e91705b8d3c891e06e9a504
[root@localhost tmp]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d6d2a9a51850 qhello "/bin/bash" 3 seconds ago Up 3 seconds 0.0.0.0:80->80/tcp qhello
[root@localhost tmp]# docker exec -it qhello /bin/bash
[root@d6d2a9a51850 /]# sh /start.sh
[root@d6d2a9a51850 /]# nohup: appending output to `nohup.out'
[root@d6d2a9a51850 /]# exit
exit
10. 通过宿主机IP访问javaweb