0%

Docker从还未入门到实践

前言

众所周知、Docker已经成为了开发者必会的技能之一,也成为家庭软路由、NAS的必装之一。大家都知道了它的优点,所以我不多叙述。说一个我使用它的原因,我有四个工作环境,两个Windows、两个MacOS、一个CentOS。仅为了每次 git clone后不想因为装依赖而抓狂。本文会用一个NGINX+PHP的环境给大家提供思路,有了思路,其他环境也是一样的搭建,没有难度,有些手把手的内容就略了。

介绍

  • 镜像
    Docker 镜像(Image),就相当于是一个 root 文件系统
  • 容器
    容器的实质是进程。
    容器内的进程是运行在一个隔离的环境里,容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间。
    容器消亡时,任何保存于容器存储层的信息都会随容器删除而丢失。所以容器不应该向其存储层内写入任何数据,官方推荐使用数据卷
  • Docker Registry
    如果我们要使用他人的镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry 就是这样的服务。

安装Docker

略~,
不过提一点,如果你的主机在国内最好安装之后的第一件是配置一下镜像加速器,提供3个参考

1
2
3
阿里云加速器(点击管理控制台 -> 登录账号(淘宝账号) -> 右侧镜像工具 -> 镜像加速器 -> 复制加速器地址)
网易云加速器 https://hub-mirror.c.163.com
百度云加速器 https://mirror.baidubce.com

Docker 命令

装完之后就可以使用 docker 命令了,比如docker ps docker images docker build等,详见官方文档 Docker command line

ps:可以借助我的 Chrome破解小插件 更好的帮助大家阅读英文文档

比如运行一个Ubuntu镜像

1
$ docker run -it --rm ubuntu:18.04 bash

然而并没有什么用,很多第三方的包括官方的图形化操作都可以让你忘却这些命令,什么情况会用到这些命令呢,举一个例子,安装一个speedtest,大可不必写Dockerfile

1
2
3
4
// run 会自动下载安装 adolfintel/speedtest 镜像
// -p 主机的8888端口映射到容器80端口
// -d 后台运行容器
docker run -p 8888:80 -d adolfintel/speedtest

学习docker如果到止步于此就太可惜了,后面的才是精华。

Dockerfile

命令行的方式肯定是满足不了我们的需求的,使用Dockerfile迫在眉睫,Dockerfile其实也是几个命令行的事情,其中的单词命令也不需要死记.

常用的指令

后面如果用到每个指令会详细讲解

ps:Dockerfile 中每一个指令都会建立一个新的镜像,下一个指令就是在上一个指令新建的镜像上面执行。如果哪天遇到了刚装的NODE、NPM 提示 not found 记得回来看这个提示。

  • FROM 指定基础镜像
  • RUN 执行命令
  • COPY 复制文件
  • ARG 构建参数
  • ENV 设置环境变量
  • WORKDIR 指定工作目录

练手1

我们来定一个需求,一个带有git环境的ubuntu镜像。通个这个需求就可以得到一个思路,写其他的dockerfile也是八九不离其中。

Dockerfile:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1:首先就是拉取一个基础镜像(镜像就是一个系统,比如Windows,同时也可以是一个安装了众多软件的Windows,甚至是你自己做的镜像)
# 2:建议养成好习惯带上版本号或者tag信息,不然将来要踩坑
FROM ubuntu:rolling

#1:在国内关键的就是设置一下镜像的软件源,比如npm设置taobao源是一样的。
#2:RUN 后面的东西和其他的shell一样写
RUN sed -i s@/archive.ubuntu.com/@/mirrors.aliyun.com/@g /etc/apt/sources.list && \
sed -i s/security.ubuntu.com/mirrors.aliyun.com/g /etc/apt/sources.list

# 使用过Ubuntu的应该都知道先更新后安装软件
RUN apt update && \
apt-get install -y git && \
apt-get clean

以上就是实现了我们的小需求了,比如安装 curl 就信手拈来了。

练手2

有两种情况下,我们会用到 Dockerfile ,其一就是配合docker-compose,其二就是docker build。其一后面说,其二你必须知道,这是基础。
Dockerfile:

1
2
3
4
FROM nginx

# 将镜像上下文中的 文件 复制到 容器目录
COPY ./package.json /var/www/

构建镜像

1
2
3
# [.] 实际上是在指定上下文的目录,千万别掉
# [:v3] 让你可以快速从众多镜像中找到该镜像
docker build nginx:v3 .

你可以使用 docker run 去运行容器了

终极奥义 Docker Compose

Compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排
Compose 定位是 「定义和运行多个 Docker 容器的应用」
· 必须使用 Dockerfile
Mac、Windows 自带 docker-compose 二进制文件

常见命令

  • build 构建(重新构建)项目中的服务容器
  • ports 主机端口映射到容器
  • restart 重启项目中的服务
  • volumes
  • depends_on 解决容器的依赖、启动先后的问题
  • expose 暴露端口,但不映射到宿主机,只被连接的服务访问
  • networks 配置容器连接的网络
  • pid 跟主机系统共享进程命名空间。打开该选项的容器之间,以及容器和宿主机系统之间可以通过进程 ID 来相互访问和操作

NGINX + PHP

先说一下我们的思路,我们需要两个Dockerfile,两个容器需要在一个网络,NGINX 可以和 PHP 通信,默认同一个网络,可以自定义。
目录结构如下

1
2
3
4
5
6
- docker
|- php-fpm
|- Dockerfile
|- nginx
|- Dockerfile
|- docker-compose.yml

docker-compose.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
version: '3.9'

services:
php-fpm:
# 镜像目录
build:
context: ./php-fpm
#本地的php配置覆盖容器内的
volumes:
- ./php-fpm/php.ini:/usr/local/etc/php/php.ini
# Nginx使用的
expose:
- "9000"
# 重启行为,可选 always 等
restart: unless-stopped
nginx:
build:
context: ./nginx
# 主机端口映射到容器
ports:
- "80:80"
- "443:443"
# nginx Dockerfile中使用到的参数
args:
- PHP_UPSTREAM_CONTAINER=php-fpm
- PHP_UPSTREAM_PORT=9000
volumes:
- [项目目录]:/var/www
- ./nginx/log:/var/log/nginx
- ./nginx/default.conf:/etc/nginx/sites-available
- ./nginx/ssl:/etc/nginx/ssl
# 此容器依赖于php-fpm启动
depends_on:
- php-fpm
restart: unless-stopped

NGINX:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 基础镜像
FROM nginx:stable-alpine

# 自定义NGINX配置
COPY nginx.conf /etc/nginx/

# 换源 alpine 的软件安装源在国内不好使
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/' /etc/apk/repositories

# 这个应该都知道
RUN apk update \
&& apk upgrade \
&& apk --update add logrotate \
&& apk add --no-cache openssl \
&& apk add --no-cache bash

RUN apk add --no-cache curl

# shell 的常规操作
RUN set -x ; \
addgroup -g 82 -S www-data ; \
adduser -u 82 -D -S -G www-data www-data && exit 0 ; exit 1

# php 的一些参数在FROM后使用,需要先声明
ARG PHP_UPSTREAM_CONTAINER=php-fpm
ARG PHP_UPSTREAM_PORT=9000

# 创建一个目录,后面会用到
RUN touch /var/log/messages

# 复制 'logrotate' 配置文件
COPY logrotate/nginx /etc/logrotate.d/

# 设置PHP的配置,并删除默认配置
RUN echo "upstream php-upstream { server ${PHP_UPSTREAM_CONTAINER}:${PHP_UPSTREAM_PORT}; }" > /etc/nginx/conf.d/upstream.conf \
&& rm /etc/nginx/conf.d/default.conf

# 可以把自己写好的shell脚本复制进去,如果没有就算了
ADD ./startup.sh /opt/startup.sh
RUN sed -i 's/\r//g' /opt/startup.sh
CMD ["/bin/bash", "/opt/startup.sh"]

# 进入容器的默认地址,通常www也是项目地址
WORKDIR /var/www

EXPOSE 80 443

PHP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# : 后面可以指定版本
FROM php:7.4-fpm
# 换源
RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list

RUN set -xe; \
apt-get update -yqq && \
pecl channel-update pecl.php.net && \
apt-get install -yqq \
apt-utils \
gnupg2 \
git \
libzip-dev zip unzip && \
docker-php-ext-configure zip && \
docker-php-ext-install zip && \
php -m | grep -q 'zip'

# 安装redis扩展,其他扩展也可以相同的方式安装
pecl install -o -f redis \
&& rm -rf /tmp/pear \
&& docker-php-ext-enable redis \

WORKDIR /var/www

CMD ["php-fpm"]

# Nginx 要用
EXPOSE 9000

完。