by Devin Yang

建立于: 7年前 ( 更新: 7年前 )

Docker的功能很类似VM(虚拟机器),但是Docker不是VM。
这是Docker与Linux核心的关系。
Docker与Linux的关系,中文图片。
 
Docker的任务流程(Build、Ship & Run)
1. Build an image: 使用一个叫Dockerfile的纯文本档,来指定我们想要东西绑进image内,诸如: 基本的OS、函式库及应用进程等,建好的image是一个只读的样板,我们可变更container,并透过commit container来生成一个新的image。
2. Ship the image: 经由Dockerh Hub或你私人的仓库(private repository),你可以非常轻易的使用docker发布这个应用进程或开发环境,
基本上这里已经有大量的官方(official)预建好的image了,随时可拿来用。
3. Run a container: 要能够跑container在一台主机上,我们需安装Docker,
可把他部署成微服务(不同的container跑不同的服务),
我的D-Laravel Project一个Laravel平台的开发环境,就是使用微服务架构。

在下图中,使用Dockerfiler创建image,通常抓现成的官方image,
用docker run可自动抓下来image并生成container,
我们可以把更多的东西放入container内,
再commit这个container成为一个新的image,再更新push到DockerHub上,
提供给别人使用。

上方投影片的出处

Docker Engine使用了Linux Kernel(核心)的新功能  Namespaces Control groups
用来隔离出任务空间,我们称为容器(Container),所以不需要像VM安装一整个作业系统。

Control groups 这里简称 Cgroups Cgroups 允许您在系统运行的用户定义的任务组(运行序)中,
分配资源(例如CPU时间,系统内存、网络频宽或这些资源的组合),
Namespaces :  用来隔离和虚拟化一系列运行序( processes )。

Create a Container

docker run 命令建容器
当我们安装好Docker后,我们可以运行如下命令(例如Ubuntu的Linux环境下,需sudo)
sudo docker run alpine echo Hello World
上方使用alpine linux创建的Docker image,只有5mb大小。
如果我们未安装这个image会自动安装,如果有装了,Docker就会直接运行,创建这个容器。
在上方的例子中并未指定tag,就会使用最新版本(latest)。
如果我们要指定版本,可补上:3.5,例如alpine:3.5。

如果不想每次都打sudo,可以运行如下命令,把你的使用者,添加docker群组。
sudo usermod -aG docker ${USER}
例如,我在AWS EC2的主机,默认的使用者是ubuntu,那么<user>就改成ubuntu,运行完后,
注销再登录bash测试,就会发现,不需要打sudo罗。
docker run hello-world
上方测试,使用hello-word的image来显示数据。

下方实际运行不需sudo了,在下方的图片中同时也发现到了,我们电脑不存在hello-world这个image时,
Docker会自动帮我们下载。

Docker Client and Daemon.

1. Client/Server的架构。
2. Client取得使用者的输入,并且送给Daemon.
3. Daemon进行builds,run及distributes containers.
4. Client及Daemon可以运行在相同的主机或不同的主机上。
5. Client有命令行Client及GUI(Kitematic)两种。

下方命令,用来查看Client及Server的版本:
docker version

Docker Containers and Images.

Images  
-是一个只读的样版,用於创建Containers。  
-是由你自己创建或是其他的Docker用户创建。  
-保存在Dockerhub或是你自己本地端的local Registry.  
Containers
-隔离的运用进程平台
-Container就是你所有应进程运行及安装的地方
-Container基於一个或多个映像档(Images)

Registry and Repository

以Docker Hub为例,Reigistry内有很多Repo,在Repo内会有很多的images.
Registry与Repository中文图片
可以把Dockerhb想像成是Docker的App Store.

Docker的效益

Sepration of concerns.
- 开发者可以专心的在於他们的Apps上(Developers focus on building their apps)。
- 系统工程师专注於部属 (System admins focus on deployment)。

Fast development cycle
- 如果需要可以轻易的开启新的container,跑更多的应用进程在主机上。

如何查看host装了那些images

可以使用 docker images 查看已安装的images。 不指定tag时,会默认使用latest版。

创建并运行Container(creating a container)

例如:
docker run ubuntu:14.04 echo "Hello World"


Container with Terminal
-使用-i及-t标记
-i 代表告诉docker去连接到container的STDIN.
-t 标记,会取得一个pseudo-terminal.

Container内的进程(process)停了,就会同时停止container.
例如:  进入bash之后离开.
docker run -it centos

所以下方的命令如下:
docker run centos echo "TEST"
这个process运行完后,container就停了。
你输入docker ps,并不会看到上方的echo "TEST"这个contaienr的process.


Container ID

用下方命令可以看运行中的containers及container id
docker ps

列出所有的containers,如果用
docker ps -a

可以看到之前所有创建的并且停止的container.

Running in Detached Mode

用-d进入detached mode
docker run -d centos ping 127.0.0.1 -c 1000
我们可以打
docker ps
查看,这个container的状态会是运行中。


运行 docker logs <short id> 可以看到结果,如果加上-f,就相当於tail -f命令。
docker logs c0299f4dc228 -f

docker run -d -P nginx 可以进行port mapping
再用 docker ps 查看
docker ps的画面

上方可以看到,创建了本地主机(host)的32856。

Commit container

先用 docker ps -a 查出所有的containers
docker ps -a
例如,上图中我有两个container
再用docker commit命令,创建新的image,如下命令
docker commit c0299f4dc228 my_new_image

记得吗?image是只读的,container才能被写数据,在进行 Debug 及测试时很有用,
透过commit想保留最新的状态到image中,这样下次run这个image时,
生成出来的container就会是我们最后commit的状态了。

我们可以用 docker images 查看是否有这个my_new_image。

一般而言,我们应该要用Dockerfile来管理我们image的变更

用Dockerfile建images

可以git clone这个repo下来测试.
https://github.com/DevinY/fpm
进入clone下来的fpm任务目录后,
cd 7.1/apache (进入7.1/apache数据夹)
这个数据夹内,会有一个Dockerfile.
我们就可以用下方命令来build自己的image了。下方的命令中,最后有一个(点).代表查看目前目录下的Dockerfile,用他来建image。
docker build -t testimage:1.0 .

如何用Dockerfile重build image实际操作,可以参考下方影片连结:
如何重build新的php-fpm image给D-Laravel使用。

运行已停止的container

我们可以用docker start来运行停止中的container,
首先如下方命令,列出所有的container:

1. docker ps -a
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS                      PORTS               NAMES
 8d2f21c4b5fc        alpine              "echo Hello World"   7 minutes ago       Exited (0) 2 minutes ago                       nervous_mestorf

2. 我们可以透过CONTAINER ID或是Name,来重新运行一次echo Hello World,加上-a是因为,
要把container内的标准输出转发出来,这样才能显示出Hello World在画面上.
docker start -a 8d2f21c4b5fc
Hello World

(题外话: 如果使用docker-compose时,docker-compose up -d时会创建运行container,docker-compose down时,会移除container)

Docker rm移除Container
docker rm 命令来移除container.
我们可以指定Container id或名称来删除container.
1. docker ps -a (列出所有的container)
2. docker rm <container name 或id>
Container必需要在停址的状态才有辨法删除,STATUS还是Up我是无法移除的。

如何取得Terminal access.

命令如下:
docker exec -i -t [container ID] /bin/bash
例如,我要进入D-Laravel的web container,那么可以用如下命令(Container ID或name都OK)
docker exec -ti dlaravel_web_1 bash
这里 dlaravel_web_1 是Container的名称
 

登录docker

如果有注册了dockerhub的帐号,就可以用
docker login

把自己的image push到dockerhub上,我们需先在dockhub上注册帐号。
docker push deviny/centos:6.6
The push refers to a repository [docker.io/deviny/centos]
网络
本地host会开8080在左边,而nginx是 container 使用port 80,
下方命令的意思代表了,我们开浏览器 localhost:8080 就能开启nginx的网页服务了。
docker run -d -p 8080:80 nginx

Mount a Volume

-当运行或创建一个container时卷宗被挂载(Volumes are mounted when creating or executing a container.
-可以被映射到主机数据夹(Can be mapped to a host directory)
-卷宗的路径必需是绝对路径(Volume paths specified must be absolute)

运行一个新的container并且挂载数据/myvolume到container的文件系统内(我们要挂载的数据夹是主机上的绝对路径)
docker run -d -P -v /myvolume nginx

运行一个新的container并且map(映射)/data/src数据夹,由主机(host)到container内的/test/src数据夹。
docker run -i -t -v /data/src:/test/src nginx

Creating a Link

(官方已列为不建议使用了,未来将被移除)
Warning: The  --link  flag is a deprecated legacy feature of Docker. It may eventually be removed. 

Docker container networking

User-defined Network,Docker官方文档参考

Docker默认会连到default bridge,container之间可用IP互通。 
如果您要让彼些容器名称(container name)可以被解析成IP,
我们需使用user-defined networks (使用者定义的网络)

User-defined networks 练习:
让Container在同一个网络下可以ping到彼此的Container Name
一、创建一个user-defined网络(这里我取名叫 dodoro_net )
docker network create --driver bridge dodoro_net

#列出网络命令
docker network ls

二、让两个Container在同一个 user-defined 的网络( dodoro_net )中,就可以用container name(容器名称)ping到彼此
1. 创建第一个数据库的container,并使用--network,设置网络为 dodoro_net
docker run --network=dodoro_net --name db -e MYSQL_ROOT_PASSWORD=secret -d mysql:5.7.17

2. 创建第二个PHP-Apache的contaner,也使用相同的 dodoro_net网络
docker run --network=dodoro_net -d --name website php:7.1.6-apache

3. 进入website container,ping mysql的container name,在step 1,我把数据库的container命名为db.
docker exec -ti website bash

4.在Website的container内。
ping db
 


上方的笔记中有提到,用 docker rm [container id或name] ,可以用来移除停止的 contaiener
那么要移除 image 怎么做呢?
可以用 rmi   (就想成 Remove Image 就对罗,要先把停止的相关container移除后,才能移除image哦)
docker rmi [Image ID]  

关念再确立

希望您能确实了解,这些命令的用途:
docker run      (创建并运行container)
docker start    (启动一个或多个停止的containers)
docker exec    (在启动中的container内,运行一个命令)

HELP

如何取得命令的帮助? 例如我们想了解docker start的用法,可以运行如下命令:
docker help start
 

Tags: docker

Devin Yang

文章内容无法一一说明,如果您有什么不了解处,欢印提问哦:)

No Comment

Post your comment

需要登入才可留言!

类似文章


docker

Docker的volume位置在那里?

我们能用 docker volume ls 列出所有的卷宗。 在OSx上用inspect来查看时,结果,我们到了Mac确找不到Mountpoint目录?

docker

[必学]在docker swarm环境必学iptabels的使用

首先Docker在Linux的环境下,Docker使用iptables规则来提供网络隔离。然而在Docker swarm mode的环境下,我们是没辨法把连接埠开在host的127.0.0.1下的,这时便可透过iptables中的DOCKER-USER chain来自定义规则罗 。

docker,phpenv

在Linux上ping不到host.docker.internal

可用docker version检查,确认版本在Docker v20.10+即可添加extra_hosts如下: