PHP 基础篇 - PHP 错误级别详解

一、前言

最近经常看到工作 2 年左右的童鞋写的代码也会出现以静态方法的形式调用非静态方法,这是个 Deprecated 级别的语法错误,代码里不应该出现的。对方很郁闷,说:为什么我的环境可以正常运行呢?

二、详解

代码会不会报错,以及你能不能看到报错信息由 PHP 配置中以下两个参数影响,目前线上主流的配置如下(php.ini 文件中):

error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off

下面详细介绍这两个参数:

1. error_reporting

首先来说说 PHP 的错误级别,代码会不会报错由 error_reporting 参数决定,PHP 的错误级别种类如下(点击查看中文版):

E_ALL             - All errors and warnings (includes E_STRICT as of PHP 5.4.0)
E_ERROR           - fatal run-time errors
E_RECOVERABLE_ERROR  - almost fatal run-time errors
E_WARNING         - run-time warnings (non-fatal errors)
E_PARSE           - compile-time parse errors
E_NOTICE          - run-time notices (these are warnings which often result
                    from a bug in your code, but it's possible that it was
                    intentional (e.g., using an uninitialized variable and
                    relying on the fact it is automatically initialized to an
                    empty string)
E_STRICT          - run-time notices, enable to have PHP suggest changes
                    to your code which will ensure the best interoperability
                    and forward compatibility of your code
E_CORE_ERROR      - fatal errors that occur during PHP's initial startup
E_CORE_WARNING    - warnings (non-fatal errors) that occur during PHP's
                    initial startup
E_COMPILE_ERROR   - fatal compile-time errors
E_COMPILE_WARNING - compile-time warnings (non-fatal errors)
E_USER_ERROR      - user-generated error message
E_USER_WARNING    - user-generated warning message
E_USER_NOTICE     - user-generated notice message
E_DEPRECATED      - warn about code that will not work in future versions
                    of PHP
E_USER_DEPRECATED - user-generated deprecation warnings 

其中 WARNING、NOTICE、DEPRECATED 等错误级别会抛出一个错误,但不会终止程序运行。

2. display_errors

再来看一下 display_errors 参数,该参数是是否展示错误信息,只有开启才会显示错误信息(值可以为 on|off、true|false、1|0)。

开发环境最好设置为开启,尽早发现问题,但生产环境一定要关闭。(点击查看中文版官方文档

3. 问题演示

下面使用 PHP 的运行时配置,改变 PHP 的 error_reporting 和 display_errors,演示上面的问题。代码如下:

<?php

// error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);  // 该级别下面的代码不会抛出错误
error_reporting(E_ALL & ~E_NOTICE);
ini_set("display_errors", "on");

class Foo
{
    public function test()
    {
        echo 'test';
    }
}

Foo::test();

运行该代码会输出 test,但同时会抛出一个 Deprecated 级别的错误。这种情况应该杜绝,规范开发,从基础做起,人人有责!


本文首发于马燕龙个人博客,欢迎分享,转载请标明出处。
马燕龙个人博客:http://www.mayanlong.com
马燕龙个人微博:http://weibo.com/imayanlong
马燕龙Github主页:https://github.com/yanlongma

PHP 基础篇 - PHP 的 BC MATH 系列数学函数

一、常见问题

用 PHP 做计算时经常会遇到精度带来的问题,下面来看两个常见的例子:

1. 运算比较

下面表达式输出的结果不是相等

<?php 

echo 2.01 - 0.01 == 2 ? '相等' : '不相等';  // 不相等

2. 类型转换

下面表达式输出的结果不是201(如果想输出你想要的结果,需要先转 string 再转 int):

<?php

$num = intval(2.01 * 100);
var_dump($num);    // int(200)

你也许会觉得很奇怪,然而这并不是 PHP 的 bug,如果想深入了解可以参考鸟哥的两篇文章:

  1. 关于PHP浮点数你应该知道的(All ‘bogus’ about the float in PHP)
  2. PHP浮点数的一个常见问题的解答

二、BC MATH

用 PHP 提供的 BC MATH 系列数学函数可以解决上面的问题。对于任意精度的数学计算, BC MATH 提供了支持用字符串表示的任意大小和精度的数字的二进制计算,最多为2147483647-1(或0x7FFFFFFF-1)。

下面用 BC MATH 提供的函数解决上面的问题。

1. 运算比较

bccomp — 比较两个任意精度的数字:

<?php

$num = bccomp(2.01 - 0.01, 2, 2);   
var_dump($num); // int(0)

注:如果两个数相等返回 0, 左边的数比较右边的数大返回 1, 否则返回-1。

2. 类型转换

bcmul — 2个任意精度数字乘法计算:

<?php

$num = bcmul(2.01, 100, 0);
var_dump($num);    // string(3) "201"
var_dump(intval($num));    // int(201)

注:返回结果为字符串类型

使用 BC MATH 系列数学函数可以让我们减少失误,避免不必要的错误,如需查看详细参数和其它函数的使用,请查阅 PHP 官方文档:http://php.net/manual/zh/book.bc.php


本文首发于马燕龙个人博客,欢迎分享,转载请标明出处。
马燕龙个人博客:http://www.mayanlong.com
马燕龙个人微博:http://weibo.com/imayanlong
马燕龙Github主页:https://github.com/yanlongma

Docker 学习笔记 - 使用 LaraDock 搭建 PHP 开发环境

一、简介

LaraDock 致力于简化创建开发环境过程,能够帮助我们在 Docker 上快速搭建 PHP 开发环境。 它预装了 Docker 镜像,为我们提供了一站式的开发环境,而不需要再去在本地机器安装 PHP、Nginx、MySQL 以及其他任何开发过程中需要的软件。

相关资料:

LaraDock 官网:http://laradock.io
LaraDock Github:https://github.com/LaraDock/laradock

二、安装

请确保已安装Docker,LaraDock 镜像的原理先不介绍,直接进入安装步骤。

1. 建立工作目录

新建 webroot 目录,laradock 和项目的代码都将放在该目录下(也可以直接使用以前的 web 根目录):

$ mkdir webroot

2. 克隆 LaraDock 代码

进入 webroot 目录,执行以下命令:

$ git clone https://github.com/Laradock/laradock.git

3. 生成 LaraDock 配置文件

进入 laradock 目录,执行以下命令:

$ cp env-example .env

如需配置 Nginx 端口、Mysql 密码等,均在 .env 文件中设置即可。

4. 开启容器

在 laradock 目录下执行以下命令,可以选择自己需要启动的容器:

$ docker-compose up -d nginx mysql redis

LaraDock 提供了很多容器,可以根据自己的选择启动。具体如下:

nginx, hhvm, php-fpm, mysql, redis, postgres, mariadb, neo4j, mongo, apache2, caddy, memcached, beanstalkd, beanstalkd-console, workspace

5. 访问 web 服务

在浏览器中访问 http://localhost,发现已经可以访问 nginx 服务,只不过报 404 而已。

三、详解

1. 404 解决方法

打开 laradock/nginx/sites/default.conf,发现 root 为 /var/www/public。在不改配置文件的情况下,只需在 webroot 目录下新建 public/index.html 文件, http://localhost即可正常访问。

2. 数据卷

通过 docker-compose.yml 文件可以看到, webroot/ 目录被映射到 workspace 容器内 /var/www 下作为数据卷。

applications:
  image: tianon/true
  volumes:
    - ${APPLICATION}:/var/www        

3. Nginx 配置虚拟主机

laradock/nginx/sites/ 目录下新建 test.conf,内容如下:

server {

    listen 80;
    listen [::]:80;

    server_name test.com;
    root /var/www/test;
    index index.php index.html index.htm;

}

webroot 目录下新建 test/index.php 文件

hosts 文件中做域名映射 127.0.0.1 test.com (docker-machine ip)

停止、构建、重启容器,在 laradock 目录下执行以下命令即可:

$ docker-compose down
$ docker-compose build nginx
$ docker-compose up -d nginx mysql redis

访问 test.com

Docker 学习笔记 - 使用 Dockerfile 创建镜像

一、概念

Dockerfile 是一种文件格式的配置文件,用户可以使用 Dockerfile 来快速创建自己的镜像。

二、示例

Dockerfile 由一行行命令语句组成,并支持以 # 开头的注释行。一般而言,Dockerfile 分为四个部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。

下面演示基于 ubuntu 镜像创建 nginx 镜像。

1. 准备 Dockerfile 和所需文件

新建目录 nginx,在该目录下新建 index.html 文件,内容为 Hello Docker!;在该目录下新建 Dockerfile 文件,内容如下:

# 基于 ubuntu 镜像
FROM ubuntu

# 维护者是 myl
MAINTAINER myl

# 安装 nginx,并设置默认 index.html 文件
RUN apt-get update
RUN apt-get install -y nginx
COPY index.html /var/www/html

# 指定镜像的默认入口
ENTRYPOINT ["/usr/sbin/nginx", "-g", "daemon off;"]

# 暴露 80 端口
EXPOSE 80

2. 生成镜像

在 nginx 目录下执行以下命令生成镜像 yanlongma/nginx

$ docker build -t yanlongma/nginx .
$ docker images
REPOSITORY                        TAG                 IMAGE ID            CREATED             SIZE
yanlongma/nginx                   latest              e79f65bd053f        24 minutes ago      216MB

成功生成镜像后,使用 docker images 即可查看到。

3. 运行镜像

使用 Dockerfile 生成的镜像和其它镜像一样使用,下面使用刚刚生成的 yanlongma/nginx 镜像启动一个容器:

$ docker run -d -p 8080:80 yanlongma/nginx
564e7509ff45416f3c99653dc79403ba4e66fdb4b078ae27de824877429f4cdc
$
$ curl http://localhost:8080
hello docker!

容器启动成功后,访问 http://localhost:8080 即可出现我们设置的 index.html 页面中内容。


本文为博主学习笔记,首发于马燕龙个人博客,欢迎分享,转载请标明出处。
马燕龙个人博客:http://www.mayanlong.com
马燕龙个人微博:http://weibo.com/imayanlong
马燕龙Github主页:https://github.com/yanlongma

Docker 学习笔记 - 端口映射与容器互联

一、前言

在实际应用中,经常会碰到需要多个服务组件容器共同协作的情况,这往往需要多个容器之间有能够互相访问到对方的服务。

除了通过网络访问外,Docker 还提供了两个很方便的功能来满足服务访问的基本需求:

  1. 端口映射:允许映射容器内应用的服务端口到本地宿主主机;
  2. 容器互联:提供了互联机制实现多个容器间通过容器名来快速访问。

二、端口映射

Docker 端口映射即映射容器内应用的服务端口到本机宿主机器。

当容器中运行一些网络应用,要让外部访问这些应用时,可以通过 -P 或 -p 参数两种方式来指定端口映射。

1. 随机映射

使用 -P 参数时,Docker 会随机映射一个端口到内部容器开放的网络端口,如下开启一个 nginx 服务:

$ docker run -d -P nginx
e93349d539119dc48dc841e117f6388d6afa6a6065b75a5b4aedaf5fb2a051fc
$ 
$ docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                   NAMES
e93349d53911        nginx               "nginx -g 'daemon ..."   11 seconds ago      Up 9 seconds        0.0.0.0:32769->80/tcp   zen_kirch

使用 docker ps 看到,本地主机的 32769 端口被映射到了容器的 80 端口,这时我们通过本机浏览器访问 http://localhost:32769 就会出现 nginx 欢迎页面。

2. 指定端口

使用 -p 参数时,可以指定要映射的端口,并且在一个指定的端口上只可以绑定一个容器。支持的格式有:

  • IP:HostPort:ContainerPort
  • IP:ContainerPort
  • HostPort:ContainerPort

下面开启一个 nginx 服务,将本机 8080 端口映射到容器的 80 端口:

$ docker run -d -p 8080:80 nginx
23e725098712d061a1382f33d6fe54da23ae37597a62f8debdd3731b5f9cc4b9
$ 
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                   NAMES
23e725098712        nginx               "nginx -g 'daemon ..."   8 seconds ago       Up 6 seconds        0.0.0.0:8080->80/tcp    frosty_ptolemy

使用 docker ps 看到,本地主机的 8080 端口被映射到了容器的 80 端口,这时我们通过本机浏览器访问 http://localhost:8080 就会出现 nginx 欢迎页面。

3. 查看映射端口

使用 docker port 命令来查看当前映射的端口配置,也可以查看到绑定的地址。命令格式如下:

$ docker port CONTAINER [PRIVATE_PORT[/PROTO]]

容器有自己的内部网络和 IP 地址,可以使用 docker inspect + 容器ID 获取容器的具体信息。

三、容器互联

容器的互联(linking)是一种让多个容器中应用进行快速交互的方式。它会在源和接收容器之间创建连接关系,接收容器可以通过容器名快速访问到源容器,而不是指定具体的 IP 地址。

下面使用 mysql 和 wordpress 镜像来搭建 wordpress 运行环境,演示容器互联的使用。

1. 自定义容器名

连接系统依据容器的名称来执行。虽然创建容器时系统会默认分配一个名字,但建议自己自定义命名。

首先启动一个 mysql 容器,使用 --name 标记自定义容器名为 db:

$ docker run --name db -d -e MYSQL_ROOT_PASSWORD=123456 mysql:latest
35bd73d4d41370bb5218818f58b7f1b89744728c4cb6317d85634abdb47da461
$ 
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
35bd73d4d413        mysql:latest        "docker-entrypoint..."   11 seconds ago      Up 10 seconds       3306/tcp            db

使用 docker ps 可以看到该容器的 NAMES 为 db。

注:-e MYSQL_ROOT_PASSWORD=123456 是为 mysql 服务设置密码,具体可以查看 mysql 镜像的使用。

2. 容器互联

使用 --link 参数可以让容器之间安全地交互。--link 的参数格式为 --link name:alias,其中 name 是要连接的容器名称,alias 是这个连接的别名。

下面启动一个 wordpress 容器,并将它连接到 db 容器:

$ docker run --name wp --link db:mysql -d -p 8080:80 wordpress:latest
d9ee6660b48f80328d14e7a2a57013e72fa8d88de8524d651e003940563e3090
$ docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
d9ee6660b48f        wordpress:latest    "docker-entrypoint..."   5 seconds ago       Up 4 seconds        0.0.0.0:8080->80/tcp   wp
35bd73d4d413        mysql:latest        "docker-entrypoint..."   18 minutes ago      Up 18 minutes       3306/tcp               db

此时,wp 容器和 db 容器建立了互联关系。

在浏览器中访问 http://localhost:8080/ 会进入 wordpress 安装程序,安装完成后进入容器 db,你会发现数据表确实被写在该容器中。

注:如提示数据库连接错误,先进入 db 容器新建数据库,如默认名为 wordpress。


本文为博主学习笔记,首发于马燕龙个人博客,欢迎分享,转载请标明出处。
马燕龙个人博客:http://www.mayanlong.com
马燕龙个人微博:http://weibo.com/imayanlong
马燕龙Github主页:https://github.com/yanlongma

Docker 学习笔记 - Docker 数据管理

一、前言

生产环境使用 Docker 的过程中,往往需要对数据进行持久化或者需要在多个容器之间进行数据共享,这必然涉及容器的数据管理操作。

容器中管理数据主要有两种方式:

  1. 数据卷(Data Volumes):容器内数据直接映射到本地主机环境;
  2. 数据卷容器(Data Volumes Containers):使用特定容器维护数据卷;

二、数据卷

数据卷是一个可供容器使用的特殊目录,它将主机操作系统目录直接映射进容器,类似 Linux 的 mount 操作。

数据卷可提供很多有用的特性,如下:

  • 数据卷可以在容器之间共享和重用,容器间传递数据将变得高效方便;
  • 对数据卷内数据的修改会立马生效,无论是容器内操作还是本地操作;
  • 对数据卷的更新不会影响镜像,解耦了应用和数据;
  • 卷会一直存在,直到没有容器使用,可以安全的卸载他。

1. 在容器内创建一个数据卷

使用 docker run 命令时,使用 -v 参数可以在容器内创建一个数据卷。多次使用 -v 标记可以创建多个数据卷。

下面使用 ubuntu 镜像创建一个容器,并创建一个数据卷挂载到容器的 /myvolumes 目录:

$ docker run -it -v /myvolumes ubuntu
root@35ebd0dccc3d:/#
root@35ebd0dccc3d:/# ls 
bin  boot  dev  etc  home  lib  lib64  media  mnt  myvolumes  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

2. 挂载一个主机目录作为数据卷

使用 -v 参数也可以挂载一个本地的已有目录到容器中作为数据卷。这个特性非常适合用于开发,下面演示使用 nginx 镜像创建一个容器运行 nginx 服务并挂载数据卷。

首先通过 nginx 镜像创建一个最基本的服务:

$ docker run --name nginx-server1 -d -p 8081:80 nginx
b3faaf910a6653fc2b2d1c99672a98bdaafd89f07eacf229e355192ee0c1cc16

这时我们通过本机浏览器访问 http://localhost:8081 会出现一个经典的 nginx 欢迎页面,如果想修改页面,只能进入容器修改,显然这并不服务我们的开发习惯。

下面通过 nginx 镜像创建一个服务,并挂载一个本地目录 /html 作为数据卷,html 目录下有一个 index.html 文件,内容为 Hello, Data Volumes !,命令如下:

$ docker run --name nginx-server2 -d -p 8082:80 -v /html:/usr/share/nginx/html nginx
ee9694da5f5364029d60e22f9136991017c76c2f40e7f8742c49173d4cc1905a

这时我们通过本机浏览器访问 http://localhost:8082 就会出现 index.html 页面的内容。修改本机 index.html 中的内容后刷新页面,发现页面的内容也随之改变,显然这更符合开发的需求。

三、数据卷容器

如果用户需要在多个容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。数据卷容器也是一个容器,但是它的目的是专门用来提供数据卷供其它容器挂载。

首先创建一个数据卷容器 dbcontainer,并在其中创建一个数据卷挂载到 /dbdata:

$ docker run --name dbcontainer -it -v /dbdata ubuntu
root@af3425b83313:/# 
root@af3425b83313:/# ls 
bin  boot  dbdata  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

然后,其它容器可以使用 --volumes-from 来挂载 dbcontainer 容器中的数据卷,例如创建 web1 和 web2 两个容器,并从 dbcontainer 容器中挂载数据卷:

$ docker run -it --name web1 --volumes-from dbcontainer ubuntu
$ docker run -it --name web2 --volumes-from dbcontainer ubuntu

这时容器 web1 和 web2 都挂载同一个数据卷到相同的 /dbdata 目录。三个容器任何一方在该目录下的写入,其它容器都能看到。


本文为博主学习笔记,首发于马燕龙个人博客,欢迎分享,转载请标明出处。
马燕龙个人博客:http://www.mayanlong.com
马燕龙个人微博:http://weibo.com/imayanlong
马燕龙Github主页:https://github.com/yanlongma

Docker 学习笔记 - Docker 仓库

一、概念

仓库(Repository)是集中存放镜像的地方,分公共仓库和私有仓库。一个容易与之混淆的概念是注册服务器(Registry)。实际上注册服务器是存放仓库的具体服务器,一个注册服务器上可以有多个仓库,而每个仓库下面可以有多个镜像。

docker-repository.jpg

例如对于仓库地址 hub.docker.com/ubuntu,其中 hub.docker.com 是注册服务器地址,ubuntu 是仓库名。

二、仓库

1. Docker Hub 官方仓库

Dcoker Hub 是 Docker 官网维护的一个公共镜像仓库。

2. 国内镜像市场

国内的镜像市场非常多,比较知名的有下面这些:

阿里云:https://dev.aliyun.com/search.html
时速云:https://hub.tenxcloud.com
网易蜂巢:https://c.163.com
DaoCloud:https://www.daocloud.io

不会翻墙的可以优先考虑使用国内镜像。

3. 搭建本地私有仓库

如果有需要可以选择自己搭建本地私有仓库。


本文为博主学习笔记,首发于马燕龙个人博客,欢迎分享,转载请标明出处。
马燕龙个人博客:http://www.mayanlong.com
马燕龙个人微博:http://weibo.com/imayanlong
马燕龙Github主页:https://github.com/yanlongma

Docker 学习笔记 - Docker 容器命令汇总

一、概念

容器是 Docker 的另一个核心概念。简单来说,容器是镜像的一个运行实例。所不同的是,镜像是静态的只读文件,而容器带有运行时需要的可写文件层。

如果认为虚拟机是模拟运行的一整套操作系统(包括内核、应用运行态环境和其他系统环境)和跑在上面的应用,那么 Docker 容器就是独立运行的一个(或一组)应用,以及它们必须的运行环境。

下面总结了常用的容器相关命令。

二、查看容器

查看容器信息相关命令,下面会用到:

docker ps        列出所有启动状态的容器
docker ps -a     列出所有容器
docker ps -qa    列出所有容器 ID

三、创建容器

1. 新建容器

使用 docker create 命令新建一个容器,会产生容器 ID,例如:

$ docker create -it ubuntu:latest
ba8bc0e5995e56a76ae0361687316ce6062247752c6754d2b16bc135e306233f

使用 docker create 命令新建的容器处于停止状态,我们可以使用 docker ps -a 查看:

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
ba8bc0e5995e        ubuntu:latest       "/bin/bash"         About a minute ago   Created                                 brave_engelbart 

2. 启动容器

使用 docker start 命令来启动一个已经创建的容器,例如启动刚创建的 ubuntu 容器(使用上面产生的容器 ID):

$ docker start ba8b
ba8b

再用 docker ps 查看,可以看到该容器处于启动状态:

$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
ba8bc0e5995e        ubuntu:latest       "/bin/bash"         18 minutes ago      Up 10 minutes                           brave_engelbart

3. 新建并启动容器

使用 docker run 可以直接新建并启动容器:

$ docker run ubuntu:latest /bin/echo 'Hello World'
Hello World

使用 -t 参数将启动一个 bash 终端,允许用户交互:

$ docker run -it ubuntu:latest /bin/bash
root@976214c9686c:/#

有时需要让 Docker 容器在后台以守护态形式运行,可以通过添加 -d 参数来实现。

四、终止容器

使用 docker stop 命令来终止一个运行中的容器。例如终止上面的 ba8b 容器:

$ docker stop ba8b
ba8b

五、进入容器

使用 docker exec 命令可以进入一个启动状态的容器中,例如下面启动 ba8b 容器并进入:

$ docker start ba8b
ba8b
$ docker exec -it ba8b /bin/bash
root@ba8bc0e5995e:/# 

六、删除容器

使用 docker rm 命令可以删除处于终止或退出状态的容器,该命令格式为:

$ docker rm [OPTIONS] CONTAINER [CONTAINER...]

选项为:

-f, --force     强行终止并删除运行中的容器
-l, --link      删除容器的连接
-v, --volumes   删除容器挂载的数据卷

例如强制删除运行中的 ba8b 容器:

$ docker rm -f ba8b
ba8b

七、导出和导入容器

1. 导出容器

使用 docker export 可以导出容器到文件,不管此时容器处于什么状态。

下面导出一个容器 ID 为 fd15 的容器到文件:

$ docker export -o test1.tar fd15

也可以:

$ docker export fd15 > test2.tar

2. 导入容器

导出的文件又可以使用 docker import 命令导入变成镜像,下面将导出的 test1.tar 文件导入到本地镜像库中:

$ docker import test1.tar  yanlongma/ubuntu:20171030

本文为博主学习笔记,首发于马燕龙个人博客,欢迎分享,转载请标明出处。
马燕龙个人博客:http://www.mayanlong.com
马燕龙个人微博:http://weibo.com/imayanlong
马燕龙Github主页:https://github.com/yanlongma

Docker 学习笔记 - Docker 镜像命令汇总

一、概念

镜像是 Docker 三大核心概念中最为重要的,是运行容器的前提。

Docker 运行容器前需要本地存在对应的镜像,如果本地不存在该镜像,Docker 会尝试先从默认镜像仓库下载(默认使用 Docker hub 公共注册服务器中的仓库),用户也可以通过配置,使用自定义的镜像仓库。

下面总结了常用的镜像相关命令。

二、搜索镜像

docker search 命令可以搜索远端仓库中共享的镜像,默认搜索官方仓库中镜像,命令如下:

$ docker search [OPTIONS] TERM

三、 获取镜像

docker pull 命令如下:

$ docker pull [OPTIONS] NAME[:TAG|@DIGEST]

从 Docker hub 获取一个 ubuntu 镜像

$ docker pull ubuntu:latest

也可以从指定的非官方仓库下载,下面是从网易蜂巢下载 ubuntu 镜像

$ docker pull hub.c.163.com/library/ubuntu:latest

四、查看镜像

1. 使用 images 命令列出镜像

可以看到下面列出了刚刚下载的两个镜像信息。

$ docker images
REPOSITORY                     TAG                 IMAGE ID            CREATED             SIZE
ubuntu                         latest              ccc7a11d65b1        2 months ago        120MB
hub.c.163.com/library/ubuntu   latest              ccc7a11d65b1        2 months ago        120MB

2. 使用 tag 命令添加镜像标签

为了方便后续工作使用特定的镜像,可以使用 tag 命令来为本地镜像任意添加新的标签。例如为 ubuntu:latest 镜像添加一个 myubuntu:latest 镜像标签:

$ docker tag ubuntu:latest myubuntu:latest

3. 使用 inspect 命令查看详细信息

docker inspect 命令可以获取镜像的详细信息,包括制作者、适用架构、各层的数字摘要等:

$ docker inspect ubuntu:latest

4. 使用 history 命令查看镜像历史

镜像文件由多个层组成,使用 history 命令可以列出各层的创建信息:

$ docker history ubuntu:latest

五、删除镜像

删除镜像使用 docker rmi 命令,格式如下,其中 IMAGE 可以是标签或 Image ID:

$ docker rmi [OPTIONS] IMAGE [IMAGE...]

删除 ubuntu:latest 镜像 :

$ docker rmi ubuntu:latest

注意,当有该镜像创建的容器存在时,镜像文件默认是无法被删除的。可以使用 -f 参数来强制删除一个存在容器依赖的镜像,但并不推荐。正确的做法是,先删除依赖该镜像的所有容器,再来删除镜像。

演示删除存在容器的镜像

使用 ubuntu:latest 镜像创建一个简单的容器来输出一段话:

$ docker run ubuntu:latest echo 'hello'

使用 docker ps -a 命令可以看到本机上存在的所有容器,可以看到后台存在一个基于 ubuntu:latest 镜像创建的且处于退出状态的容器 bbb5ae0d3851:

$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
bbb5ae0d3851        ubuntu              "echo hello"        22 seconds ago      Exited (0) 21 seconds ago                       unruffled_swartz

如果删除该镜像,Docker 会提示有容器正在运行,无法删除:

$ docker rmi ubuntu:latest
Error response from daemon: conflict: unable to remove repository reference "ubuntu:latest" (must force) - container bbb5ae0d3851 is using its referenced image ccc7a11d65b1

正确的做法是,首先应该删除容器 bbb5ae0d3851,再删除镜像(ubuntu:latest 镜像ID 为 ccc7a11d65b1,此处用镜像ID删除)

$ docker rm bbb5ae0d3851
$ docker rmi ccc7a11d65b1

六、创建镜像

创建镜像的方法主要有三种:

1. 基于已有镜像的容器创建

该方法主要使用 commit 命令,格式如下:

$ docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

2. 基于本地模板导入

用户也可以直接从一个操作系统模板文件导入一个镜像,主要使用 import 命令,格式如下:

$ docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]

3. 基于 Dockerfile 创建

后面会单独总结

七、存出和载入镜像

1. 存出镜像

导出镜像到本地文件,可以使用 docker save 命令,例如导出本地的 ubuntu:latest 镜像为文件 ubuntu_latest.tar

$ docker save -o ubuntu_latest.tar  ubuntu:latest

之后,用户可以通过 ubuntu_latest.tar 文件将该镜像分享给其他人。

2. 载入镜像

可以使用 docker load 将导出的 tar 文件导入到本地镜像库,例如从文件 ubuntu_latest.tar 导入镜像到本地镜像列表:

$ docker load --input ubuntu_latest.tar 

或:

$ docker load < ubuntu_latest.tar 

八、上传镜像

可以使用 docker push 命令上传镜像到仓库,默认上传到 Docker Hub 官方仓库。

首先需要在 Docker Hub 注册账号,第一次上传需要登录,命令如下:

$ docker login

只能将镜像上传到自己的账号下面,比如我的用户名为 yanlongma,如果想上传本地的 ubuntu:latest 镜像,需要先添加新标签 yanlongma/ubuntu:latest,然后用 docker push 命令上传镜像:

$ docker tag ubuntu:latest yanlongma/ubuntu:latest
$ docker push yanlongma/ubuntu:latest

本文为博主学习笔记,首发于马燕龙个人博客,欢迎分享,转载请标明出处。
马燕龙个人博客:http://www.mayanlong.com
马燕龙个人微博:http://weibo.com/imayanlong
马燕龙Github主页:https://github.com/yanlongma

Docker 学习笔记 - Docker 核心概念与安装

一、Docker 三大核心概念

Docker 三大核心概念如下,只有理解了这三个核心概念,才能顺利的理解 Docker 容器的整个生命周期。

1. 镜像(Image)

Docker 镜像类似于虚拟机镜像,可以将它理解为一个只读的模板。例如,一个镜像可以包含一个基本的操作系统环境,里面仅安装了 Apache 应用程序(或用户需要的其他软件)。可以把它称为一个 Apache 镜像。

2. 容器(Container)

Docker 容器类似于一个轻量级的沙箱,Docker 利用容器来运行和隔离应用。简单来说,容器是镜像的一个运行实例。所不同的是,镜像是静态的只读文件,而容器带有运行时需要的可写文件层。

3. 仓库(Repository)

Docker 仓库类似于代码仓库,它是 Docker 集中存放镜像文件的场所。

二、安装 Docker

1. 版本选择

Docker 官网 上可以看到,目前 Docker 分 CE 和 EE 两种,每种支持的平台也略有不同,大家可以根据自己的需要进行选择,学习选择 CE 版本即可。详情如下图:

docker-ce-ee.jpg

2. 安装

安装很简单,大家到 Get Docker 页面下载对应平台的安装包安装即可。需要注意的是 macOS 10.10.3 之前版本、windows7和8 需要通过虚拟机方式来支持,下载对应平台的 Docker Toolbox 安装即可。

3. 检测是否安装成功

打开终端,执行 docker version,如出现如下信息则安装成功:

$ docker version
Client:
 Version:      17.09.0-ce
 API version:  1.32
 Go version:   go1.8.3
 Git commit:   afdb6d4
 Built:        Tue Sep 26 22:40:09 2017
 OS/Arch:      darwin/amd64

Server:
 Version:      17.09.0-ce
 API version:  1.32 (minimum version 1.12)
 Go version:   go1.8.3
 Git commit:   afdb6d4
 Built:        Tue Sep 26 22:45:38 2017
 OS/Arch:      linux/amd64
 Experimental: true

三、相关链接

Docker 官网:https://www.docker.com
Get Docker:https://www.docker.com/get-docker
Docker Toolbox:https://www.docker.com/products/docker-toolbox


本文为博主学习笔记,首发于马燕龙个人博客,欢迎分享,转载请标明出处。
马燕龙个人博客:http://www.mayanlong.com
马燕龙个人微博:http://weibo.com/imayanlong
马燕龙Github主页:https://github.com/yanlongma