安装Docker

首先要安装Docker。Docker底层使用的是Linux的容器技术。

所以,为了能够使用Docker,我们需要一台安装了兼容版本的Linux内核和二进制文件的最小化功能宿主机。

笔者这里使用了CentOS 7操作系统。

Step1. Update Docker Package Database

更新yum的repo:

sudo yum check-update

Step 2: Install the Dependencies

接下来安装Docker的依赖库:

sudo yum install -y yum-utils device-mapper-persistent-data lvm2

The yum-utils switch adds the yum-config-manager. Docker uses a device mapper storage driver, and the device-mapper-persistent-data and lvm2 packages are required for it to run correctly.

yum-utils会安装yum-config-manager,用于我们下一步配置Docker repo。
Docker需要使用设备存储映射驱动(device mapper storage driver),因此,为了Docker能够正确的运行,我们需要安装device-mapper-persistent-data 和 lvm2 packages。

Step 3: Add the Docker Repository to CentOS

sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

这个yum repo会让我们安装最新版本的Docker。

Step 4: Install Docker On CentOS Using Yum

sudo yum install docker

Step: 5 Manage Docker Service

虽然我们安装了Docker,但是Docker并没有启动。Docker是作为一种服务来运行的:

sudo systemctl start docker
sudo systemctl enable docker

OK,我们就完成了Docker的安装,并启动了Docker服务。

安装Docker-compose

接下来我们来安装Docker-compose。

Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.

Compose是定义和运行多容器Docker应用程序的工具,使用Compose,您可以使用YAML文件来配置应用程序的服务,然后,使用单个命令创建并启动配置中的所有服务

在Linux系统中,安装Docker-compose由两种方式:

方法一:

sudo curl -L "https://github.com/docker/compose/releases/download/1.25.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

To install a different version of Compose, substitute 1.25.1 with the version of Compose you want to use.

为Docker-compose添加可执行权限:

sudo chmod +x /usr/local/bin/docker-compose

方法二:

利用pip:

#安装pip
$yum -y install epel-release
$yum -y install python-pip
#确认版本
$pip --version
#更新pip
$pip install --upgrade pip
#安装docker-compose
$pip install docker-compose
#查看版本
$docker-compose version

注意在安装Docker-compose的时候,我们需要安装一下系统的编译支持:

yum install gcc
yum install gcc-c++
yum install python-devel -y

编写Docker file

Docker file用于Docker编译我们的工程。在编写Docker的时候,要注意的是,Docker file的路径,全部是基于Docker file所在目录的。

下图是docker file的目录配置:

最外层的Docker file是用来配置我们的Web 工程,基于python:3.6的镜像:

FROM python:3.6RUN mkdir /ai_mei_jiaWORKDIR /ai_mei_jiaADD . /ai_mei_jiaRUN pip3 install -r requirements.txtEXPOSE 8080ENV DJANGO_SETTINGS_MODULE=ai_mei_jia.settings.pro# 赋予start.sh可执行权限
RUN chmod u+x start.sh#容器启动后要执行的命令
CMD bash ./start.sh

requirements.txt中配置需要Django工程依赖的python库:

uwsgi==2.0.18
psycopg2-binary==2.8.4
Django==3.0.1
djangorestframework==3.11.0
pillow==6.2.1
django-rest-auth==0.9.5
djangorestframework-jwt==1.11.0
django-redis==4.11.0
aliyun_python_sdk_core

start.sh用来在容器启动时,执行必要的shell命令:

python manage.py collectstatic --noinput &&
python manage.py makemigrations &&
python manage.py migrate &&
uwsgi --ini config/uwsgi.ini

在Nginx目录中,我们配置了Nginx需要的Docker file,主要是将我们的Nginx配置文件,拷贝到Nginx容器中:

FROM nginx# 对外暴露端口
EXPOSE 80 8000COPY ./config/ai_mei_jia_nginx.conf /etc/nginx/conf.d/

在Redis目录中,配置了Redis需要的Docker file:

FROM redis:5.0
COPY redis.conf /usr/local/etc/redis/redis.conf
CMD [ "redis-server", "/usr/local/etc/redis/redis.conf" ]

编写Docker-compose.yml

我们编写好Docker file之后,就可以在Docker-compose.yml文件中,将这些镜像组织起来了:

version: '3'services:db:image: postgres:12restart: alwaysvolumes:- ./postgredata:/var/lib/postgresql/dataenvironment:- POSTGRES_USER=eshi- POSTGRES_DB=ai_mei_jia_db- POSTGRES_PASSWORD=sw123!redis:image: redis:5restart: alwayscommand: redis-serverports:- "6379:6379"volumes:- ./redisdata:/dataweb:build: .restart: alwaysports:- "8080:8080"volumes:- .:/ai_mei_jia- /tmp/:/tmp/depends_on:- db- redisnginx:build: ./nginxports:- "80:80"volumes:- ./nginx/config:/etc/nginx/conf.d- /tmp/:/tmp/- ./media:/usr/share/nginx/html/media- ./static:/usr/share/nginx/html/staticrestart: alwaysdepends_on:- web

对于镜像的构建,docker-compose有两种方式:buildimage。build的方式后面跟的内容是构建镜像所需的Docker file的路径,如:

...
nginx:build: ./nginx...

而image的方式则是之间使用仓库中已有的镜像,后面跟的内容是镜像的仓库路径,这种情况是不需要本地构建镜像的,而是直接将仓库中的镜像pull到本地。如:

...
redis:image: redis:5...

我们用depends_on设定了容器之间的依赖关系,在容器启动时,会根据depends_on的顺序来依次启动容器。需要注意的是,这里的容器启动,并不能够确保容器内的数据库能够完全启动,因此可能会发生web连接不上db的问题。

我们用volumes设定了宿主机与容器之间的卷映射,这样做的好处是,我们能够直接在宿主机修改文件内容,如服务器的源代码,或一些配置文件,而不必重新构建镜像。注意,这里映射的宿主机的路径,是相对于docker-compose.yml文件的

现在,我们在docker-compse文件所在的目录,执行:

docker-compose build

来构建我们的镜像吧!

Docker Networking

在docker-compose文件中,我们一共构建了4个镜像:
db, redis, web, nginx。(当然最后的镜像名称并不是这4个名称,这4个名称主要是用来在docker-compose中容器间的通信)。
我们用depend-on设置了容器之间的依赖关系。

那么,这些容器间是如何通信的呢?

在Docker中,容器之间的通信通过网络创建,这被称为Docker Networking,也是Docker 1.9发布版本中的新功能。

当我们用docker-compose up 启动一组容器后,如果没有指定名称,则docker会默认创建一个Docker Networking网络,容器间通过这个网络来通信。可以理解为Docker创建了一个虚拟的局域网,docker-compose中的每个容器,都是这个局域网内的一个主机,由自己的ip,容器通过这个虚拟局域网来通信。

我们可以用下面命令来查看当前Docker中的networking 列表:

 docker network ls
NETWORK ID          NAME                      DRIVER              SCOPE
63ba93338b3a        ai_mei_jia_copy_default   bridge              local
60090ef6f4ce        ai_mei_jia_default        bridge              local
a5395928d7f8        bridge                    bridge              local
abf7689564f0        host                      host                local
bb9594ed8810        none                      null                local

network分为两种,一种是bringe,一种是overlay。通过overlay模式,我们可以使不同的宿主机间的容器进行通信。在这里,我们只是在同一个宿主机上设置了一个bridge网络。

我们可以通过inspect命令来查看一个网络中的情况:

 docker network inspect ai_mei_jia_copy_default
[{"Name": "ai_mei_jia_copy_default","Id": "63ba93338b3a86d23723209077b2afac1b4afa94c673e63113153f8031b30e71","Created": "2020-01-21T14:19:06.957571863+08:00","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": null,"Config": [{"Subnet": "172.19.0.0/16","Gateway": "172.19.0.1"}]},"Internal": false,"Attachable": true,"Containers": {"5354921a5c3caa027f88292913f8924a4d627e9a282a115444a73e468d09f357": {"Name": "ai_mei_jia_copy_nginx_1","EndpointID": "0a4f9714d4f7a3da0847dc2d50fad39b26e8a211b9b9c01091cfdfc2ae20bad5","MacAddress": "02:42:ac:13:00:05","IPv4Address": "172.19.0.5/16","IPv6Address": ""},"6ac4a5db1508ac65f9dbe0fea5c698726703a9f1ba23b83a04d9495c298ba75f": {"Name": "ai_mei_jia_copy_redis_1","EndpointID": "df03597ad99434dd735c2bf78cf01777a16ae6c6feaf742c67ca6624ee0ae870","MacAddress": "02:42:ac:13:00:02","IPv4Address": "172.19.0.2/16","IPv6Address": ""},"cc56e63dbb76d468a1338b1c621807604fc75ac4e3797067bf544500c2b4e41f": {"Name": "ai_mei_jia_copy_db_1","EndpointID": "67e6f297948f62783737807b577ede01f52fa61b603508f8190b9fd21bd70baf","MacAddress": "02:42:ac:13:00:03","IPv4Address": "172.19.0.3/16","IPv6Address": ""},"e852a487cf3ab64fd373ec1f6158fe1f58ac02bfe1201c1ca78afa1f4f8fa50d": {"Name": "ai_mei_jia_copy_web_1","EndpointID": "8e4b4ae0034e207b46bf6b248ab6219bd2622ce5cdf4e6ab94aa345972ab1308","MacAddress": "02:42:ac:13:00:04","IPv4Address": "172.19.0.4/16","IPv6Address": ""}},"Options": {},"Labels": {"com.docker.compose.network": "default","com.docker.compose.project": "ai_mei_jia_copy","com.docker.compose.version": "1.25.1"}}
]

当容器通过docker-compse连接起来后,容器之前的地址就可以用docker-compose配置文件中的名称来代替了,如,在Django的配置文件中,我们可以设置redis和Postgresql的地址为:

DATABASES = {'default': {'ENGINE': 'django.db.backends.postgresql',...,'HOST': 'db', # set in docker-compose.yml'PORT': 5432 # default postgres port}
}
CACHES = {'default': {'BACKEND': 'django_redis.cache.RedisCache','LOCATION': 'redis://redis:6379/1',  # redis(容器)'OPTIONS': {'CLIENT_CLASS': 'django_redis.client.DefaultClient',}}
}

将镜像上传至阿里云镜像仓库

当本地镜像构建完毕后,我们就需要将镜像上传当仓库,用来在其他的机器上使用我们的镜像。Docker由官方的镜像网站Docker Hub。由于其是国外的网站,上传下载都比较慢,因此我们选用了国内的阿里云Docker镜像网站。

在阿里云的控制台搜索容器镜像服务:

开通服务后,创建一个镜像仓库:

当镜像创建完毕后,你就会得到一个镜像仓库的地址,copy下。

回到宿主机,登录我们刚才的阿里云容器仓库:

sudo docker login --username=erenshi registry.cn-hangzhou.aliyuncs.com

为我们本地的镜像打tag:

docker tag ai_mei_jia_web:v3 registry.cn-hangzhou.aliyuncs.com/ai_mei_jia_test/ai_mei_jia_test1/ai_mei_jia_web:v3

push 到仓库:

docker push registry.cn-hangzhou.aliyuncs.com/ai_mei_jia_test/ai_mei_jia_test1/ai_mei_jia_web:v3

等待一会儿,阿里云的容器仓库里就有我们的镜像啦。不过很奇怪的是,在阿里云的控制台中,并看不到我们上传的镜像,这也许是阿里云的一个bug:

现在,就来修改docker-compose文件中的内容,将本地的build指令,改为使用仓库中的镜像:

web:build: .

修改为:

web:image: registry.cn-hangzhou.aliyuncs.com/ai_mei_jia_test/ai_mei_jia_test1/ai_mei_jia_web:v3

nginx:build: ./nginx

修改为:

nginx:image: registry.cn-hangzhou.aliyuncs.com/ai_mei_jia_test/ai_mei_jia_test1/ai_mei_jia_copy_nginx:v1

OK! 让我们到新的宿主机上,将docker-compose.yml拷贝过来,并将我们的web源码拷贝到对应的目录(因为我们在docker-compose中设置了卷映射,源码会完全映射到web容器的work 目录,所以如果不将源码复制过来,web容器会报找不到文件错误)。

编配镜像:

docker-compose build

编配镜像,因为我们此时的镜像都采用了image模式编配,因此build并不会执行任何事情,而是会等到真正运行的时候,docker才会到仓库中将需要的镜像pull下来。

运行镜像:

docker-compose up -d

这时docker会到仓库将镜像pull到本地,并运行容器。

输入

docker ps

查看容器的运行状态,如果正常的话,应该都是up状态:

如果发现有的容器一直是Restaring状态,有可能是容器内部在启动时发生了错误。这时候可以执行:

docker logs CONTAINER_ID

来查看容器输出的log。

如果还有其他的问题,我们还可以通过命令:

docker exec -it CONTAINER_ID /bin/bash

登录到容器内部。

可能的问题

在docker环境中,可能的问题多是由于Linux防火墙或SELinux引起的。

对于防火墙,我们可以通过命令

firewall-cmd -state

来查看防火墙的运行状态,
并通过:

sudo firewall-cmd --zone=public --permanent --add-port=80/tcp
sudo firewall-cmd --reload

来允许http协议通过80端口来访问我们的服务器。

对于SELinux,我们可以通过命令

sestatus

来查看SELinux的运行状态,并通过修改SELinux的配置文件:

vim /etc/selinux/config

来设置是否启动SELinux。设置完毕后,需要通过命令

shutdown -r now

重启机器来使设置生效。

容器无法解析域名

当我们在容器内部用域名访问外网时,有时可能出现name unresolved的问题。如笔者在使用阿里云SDK发送短信时,SDK提示name unresolved错误。这是因为容器的DNS没有设置正确引起的,这多发生在用虚拟机运行Linux的情况下。

这时候,我们需要修改docker的deamon.json文件:

vim /etc/docker/daemon.json

添加宿主机的DNS地址:

{"dns": ["192.168.57.5"],
}

然后重启docker服务:

systemctl restart docker

无法访问服务器

但我们在阿里云服务器正确启动服务器容器后,通过浏览器访问服务器网址,却发现无法访问服务器。这是为啥呢?

原来是因为阿里云服务器的安全组默认没有开放80端口的缘故。这时候我们需要到阿里云ECS控制台,选择我们的服务器实例,进入后,选择本实例安全组:

内网入方向全部规则下面,添加80端口(即Nginx所监听的端口号):

再次尝试访问网址,这次服务器应该就通了!

小白服务器编程指北(2)——用Docker编配你的服务器环境相关推荐

  1. es6 filter函数的用法_Python 函数式编程指北,不只是面向对象哦!超级详细!

    Python 函数式编程指北, 不只是面向对象哦 了解在Python中如何使用 lambda, map, filter 和 reduce 函数来转换数据结构 Photo by Markus Spisk ...

  2. 2008年度LINUX与UNIX SHELL编程指北系列大片

    2008年度LINUX与UNIX SHELL编程 指北 系列大片 前言:这个世界是公平的,机会是平等的,学习的机会人人都有,只要你有不甘平庸的上进之心,定会成功! 主演:rootman rootman ...

  3. 【后台技术】异步编程指北,问题和重点

    导语:同步.异步,并发.并行.串行,这些名词在我们的开发中会经常遇到,这里对异步编程做一个详细的归纳总结,希望可以对这方面的开发有一些帮助. 内容大纲: 1.几个名词的概念 多任务的时候,才会遇到的情 ...

  4. 服务器编程入门(11)TCP并发回射服务器实现 - 单线程select实现

    问题聚焦: 当客户端阻塞于从标准输入接收数据时,将读取不到别的途径发过来的必要信息,如TCP发过来的FIN标志. 因此,进程需要内核一旦发现进程指定的一个或多个IO条件就绪(即输入已准备好被读取,或者 ...

  5. 门禁系统服务器是指什么设备,浅述门禁系统服务器相关要点

    门禁系统服务器作为整个系统的核心,一直处于非常关键性的地位,给我们的硬件设施和软件都进行着最大化的认知过程,从整体的进程上进行相关讨论发现,门禁系统服务器具有一些内容要点要进行根本性的了解. 首先对于 ...

  6. Python 函数式编程指北,不只是面向对象哦

    了解在Python中如何使用 lambda, map, filter 和 reduce 函数来转换数据结构 Photo by Markus Spiske on Unsplash 面向对象的编程通过封装 ...

  7. oracle 删除函数对象不存在_Python 函数式编程指北,不只是面向对象哦

    了解在Python中如何使用 lambda, map, filter 和 reduce 函数来转换数据结构 Photo by Markus Spiske on Unsplash 面向对象的编程通过封装 ...

  8. 用java有理数类包含加减乘除,7.1 面向对象的简介 - VimL 语言编程指北路

    面向对象是一种编程思想,并不特指某种编程语言.所以不必惊讶用 VimL 也能以面向 对象的方式来写代码.本章先简单介绍一下面向对象的编程思想,再探讨如何利用 VimL 现有的特性实现面向对象编程.最后 ...

  9. 网站服务器端指的是什么,web客户端和服务器分别指什么

    web客户端和服务器分别指什么 内容精选 换一换 华为云帮助中心,为用户提供产品简介.价格说明.购买指南.用户指南.API参考.最佳实践.常见问题.视频帮助等技术文档,帮助您快速上手使用华为云服务. ...

最新文章

  1. 《杀破狼》:可能是华语动作电影最后的绝唱!
  2. 将英文man替换为中文man最简单的方法
  3. ASP.NET上传文件对文件类型的高级判断
  4. php 24点算法,PHP实现简单的24点游戏
  5. 线性表易错点与线性表程序设计易错点
  6. 零基础学Python(第五章 运算符)
  7. 数据可视化及其重要性:Python
  8. PyFlink 开发环境利器:Zeppelin Notebook
  9. 带你认识7种云化测试武器
  10. 颜值牛逼惨了的swagger-UI
  11. 文本挖掘与matlab,文本挖掘与数据挖掘:发现差异
  12. 学生专用计算机怎么调时间,学生计算器怎么调时间
  13. 【机器学习】决策树(Decision Tree)
  14. 2016年,续航新能量
  15. 16bit灰度图像映射到8bit显示
  16. 中国互联网企业VS美国互联网企业
  17. Python中graphics不存在,解决办法
  18. 用python实现身份证号校验系统
  19. 【智能优化算法】基于沙猫群优化算法求解单目标优化问题附matlab代码
  20. 英语六级段落匹配技巧

热门文章

  1. 日常编程笔记 | 2022.10.1 | 归并排序_一无序列
  2. 双引擎强悍!QQ电脑管家4.6 Beta1实测
  3. 单项冠军企业申报条件及奖励政策
  4. 3、如何理解超平面?
  5. ABP框架源码中的Linq扩展方法
  6. STM32学习日记3---定时器TIM3重映射PWM波呼吸灯实验
  7. windows server2008 设置允许特定端口通过防火墙
  8. 不查日历怎么知道任何一天是星期几
  9. 06-树(tree)
  10. 2019年:两成开发者月薪超1.7万,算法工程师最紧缺