【云原生 | 拓展02】在单台宿主机上管理Docker容器

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: Docker依赖的技术实际上已经以不同形式存在一段时间了,但Docker是那个成功抓住技术行业兴趣点的解决方案。这把Docker推到了一个令人羡慕不已的位置——社区先驱们完成

🍁作者简介:🏅云计算领域优质创作者🏅新星计划第三季python赛道第一名🏅 阿里云ACE认证高级工程师🏅

✒️个人主页:小鹏linux

💊个人社区:小鹏linux(个人社区)欢迎您的加入!

目录

1. 简单的单台宿主机

2. 为什么要使用systemd管理宿主机上的容器

3. 安装systemd

4.用systemd设置一个简单的Docker应用程序

5. 使用systemd编排宿主机上的容器

👑👑👑结束语👑👑👑


Docker依赖的技术实际上已经以不同形式存在一段时间了,但Docker是那个成功抓住技术行业兴趣点的解决方案。这把Docker推到了一个令人羡慕不已的位置——社区先驱们完成了这一系列工具的开创工作,这些工具又吸引使用者加入社区并不断地回馈社区,形成了一个自行运转的生态系统。

有多种不同的方式来组合编排工具的家族树。图下图展示了我们熟悉的一些工具。


树的根节点是docker run命令,这是启动容器最常用的方式。Docker家族的几乎所有工具都衍生于这一命令。树的左侧分支上的工具将一组容器视为单个实体,中间分支的工具借助systemd或服务文件管理容器,右侧分支上的工具将单个容器视为单个实体。沿着这些分支往下,这些工具做的事情越来越多,例如,它可以跨多台宿主机工作,或者让用户远离手动部署容器的繁琐操作。

image.gif

大家可能会注意到图 9-1 中看似孤立的两个区域——Mesos和 Consul/etcd/Zookeeper组。Mesos是一个有趣的东西,它在Docker之前就已经存在,并且它对Docker的支持是一个附加功能,而不是核心功能。虽然它做得不 错,但是也需要仔细评估,如果仅仅是从功能特性上来看,用户可能在其他工具中也想要有这些。相比之下,Consul、etcd和Zookeeper根本不是编排工具。相反,它们为编排提供了重要的补充功能——服务发现。

1. 简单的单台宿主机


在本地机器上管理容器可能是一种痛苦的体验。Docker为长期运行的容器提供的管理功能比较原始,而启动带有链接和共享卷的容器更是一个令人沮丧的手动过程。

2. 为什么要使用systemd管理宿主机上的容器

在这一技巧里,我们将使用systemd配置一个简单的Docker服务。如果大家熟悉systemd,跟进本章内容将会相对容易些,但我们假设大家之前对此工具并不了解。

对于一个拥有运维团队的成熟公司来说,֯使用systemd控制Docker是很有用的,因为他们更喜欢沿用自己已经

了解并且已经工具化的经过生产验证的技术。

systemd是一个系统管理的守护进程,它在前段时间取代了Fedora的SysVinit脚本。它可以通过独立单元的形式管理系统上的所有服务——从挂载点到进程,甚至到一次性脚本。它在被推广到其他发行版和操作系统后变得愈加受欢迎,虽然在一些系统上安装和启用它可能还有问题。设置systemd时,别人使用systemd过程中遇到类似问题的处理经验值得借鉴。

3. 安装systemd

如果用户的宿主机系统上还没有安装systemd(可以运行systemctl status命令来检查,查看是否能得到正确的响应),可以使用标准包管理工具将其直接安装到宿主机的操作系统上。如果不太习惯以这种方式与宿主机系统交 互,推荐使用Vagrant来部署一个已经安装好systemd的虚拟机,如下:

$ mkdir centos7_docker                        #创建并进入一个新的目录
$ cd centos7_docker                           
$ vagrant init jdiprizio/centos-docker-io     #将目录初始化成一个Vagrant环境,指定Vagrant镜像
$ vagrant                                     #启动虚拟机
$ vagrant ssh                                 #采用SSH的方式登入虚拟机

image.gif

4.用systemd设置一个简单的Docker应用程序

现在机器上安装好了systemd和Docker,systemd通过读取INI格式的配置文件来工作。

INI文件:INI文件是一种简单的文本文件,其基本结构由节、属性和值组成

首先以root身份创建一个服务文件/etc/systemd/system/todo.service

在这个文件里告诉systemd在宿主机的8000端口上运行一个名为todo的Docker容器。

[Unit]                                         #Unit部分定义了systemd对象的通用信息
Description=Simple ToDo Application After=docker.service #Docker服务启动之后立即启动这个单元
Requires=docker.service                        #该单元成功运行的前提是运行Docker服务
[Service]                                      #Service 部分定义了与systemd 服务单元类型相关的配置信息
Restart=always                                 #如果服务终止了,总是重启它
ExecStartPre=/bin/bash \
-c '/usr/bin/docker rm -f todo || /bin/true'   #ExecStartPre 定义了一个命令。该命令会在该单元启动前运行。要确保启动该单元前容器已经删掉,可以在这里删除它
ExecStartPre=/usr/bin/docker pull dockerinpractice/todo #确保运行容器之前已经下载了该镜像
ExecStart=/usr/bin/docker run --name todo \
-p 8000:8000 dockerinpractice/todo             #ExecStart 定义了服务启动时要运行的命令
ExecStop=/usr/bin/docker rm -f todo            #ExecStop 定义了服务停止时要运行的命令
[Install]                                      #Install 部分包含了启用该单元时systemd 所需的信息
WantedBy=multi-user.target                     #告知systemd当进入多用户目标环境的时候希望启动该服务单元

image.gif


从该配置文件可以非常清楚地看出,systemd为进程的管理提供了一种简单的声明式模式,将依赖管理的细节交给systemd服务去处理。但这并不意味着用户可以忽视这些细节,只是它确实为用户提供了很多方便的工具来管理Docker(和其他)进程

启动一个新的服务单元即是调用systemctl enable命令。如果希望系统启动的时候该服务单元能够自动启动,也可以在systemd的multi-user.target.wants目录下创建一个符号链接。一旦完成,就可以使用systemctl start来启动该单元了:

$ systemctl enable /etc/systemd/system/todo.service
$ ln -s '/etc/systemd/system/todo.service' \
'/etc/systemd/system/multi-user.target.wants/todo.service'
$ systemctl start todo.service

image.gif

然后只要等它启动。如果出现问题会有相应的提示。

可以使用systemctl status命令来检查是否一切正常。它会打印一些关于该服务单元的通用信息,如进程运行的时间以及相应的进程 ID,紧随其后的是该进程的日志信息。通过以下例子可以中看出Swarm服务端在8000端口下正常启动:

[root@centos system]# systemctl status todo.service 
todo.service - Simple ToDo Application
  Loaded: loaded (/etc/systemd/system/todo.service; enabled)
  Active: active (running) since Wed 2015-03-04 19:57:19 UTC; 2min 13s ago 
Process: 21266 ExecStartPre=/usr/bin/docker pull dockerinpractice/todo 
➥ (code=exited, status=0/SUCCESS)
Process: 21255 ExecStartPre=/bin/bash -c /usr/bin/docker rm -f todo ||
➥ /bin/true (code=exited, status=0/SUCCESS)
Process: 21246 ExecStartPre=/bin/bash -c /usr/bin/docker kill todo || 
➥ /bin/true (code=exited, status=0/SUCCESS)
Main PID: 21275 (docker)
  CGroup: /system.slice/todo.service
        ??21275 /usr/bin/docker run --name todo 
        ➥ -p 8000:8000 dockerinpractice/todo
Mar 04 19:57:24 centos docker[21275]: TodoApp.js:117:
➥ // TODO scroll into view
Mar 04 19:57:24 centos docker[21275]: TodoApp.js:176:
➥ if (i>=list.length()) { i=list.length()-1;} // TODO .length 
Mar 04 19:57:24 centos docker[21275]: local.html:30:
➥ <!-- TODO 2-split, 3-split -->
Mar 04 19:57:24 centos docker[21275]: model/TodoList.js:29:
➥ // TODO one op - repeated spec? long spec?
Mar 04 19:57:24 centos docker[21275]: view/Footer.jsx:61:
➥ // TODO: show the entry's metadata
Mar 04 19:57:24 centos docker[21275]: view/Footer.jsx:80:
➥ todoList.addObject(new TodoItem()); // TODO create default
Mar 04 19:57:24 centos docker[21275]: view/Header.jsx:25:
➥ // TODO list some meaningful header (apart from the id)
Mar 04 19:57:24 centos docker[21275]: > todomvc-swarm@0.0.1 start /todo
Mar 04 19:57:24 centos docker[21275]: > node TodoAppServer.js
Mar 04 19:57:25 centos docker[21275]: Swarm server started port 8000

image.gif

本技巧中介绍的一些原理不只适用于systemd,大部分进程管理器,包括其他的init系统,都可以采用类似的方式来配置。

5. 使用systemd编排宿主机上的容器


不同于docker-compose(编写本书时),systemd已经是一个用于生产的成熟技术。在本技巧中,我们将展示如何使用systemd来实现和docker-compose类似的本地编排功能。

如果大家在学习如下技巧的时候遇到问题,可能需要升级一下Docker版本,1.7.0及以上版本应该会正常工作

展示了我们计划实现的systemd服务单元配置中的依赖:

image.gif

如下代码展示了sqliteserver服务的代码。像以前一样,它依赖Docker服务,但和前面介绍的to-do实例有一些不同之处。

[Unit]                                                    #Unit小节定义了该systemd对象的通用信息
Description=SQLite Docker Server After=docker.service     #Docker服务启动之后启动该单元
Requires=docker.service                                   #为了让该服务正常运行,Docker服务必须处于正常运行状态
[Service]
Restart=always
ExecStartPre=-/bin/touch /tmp/sqlitedbs/test              #这几行代码确保服务启动之前SQLite的数据库文件是存在的,touch命令行之前的-告诉systemd:如果该命令返回错误代码则表明启动失败
ExecStartPre=-/bin/touch /tmp/sqlitedbs/live 
ExecStartPre=/bin/bash \ 
-c '/usr/bin/docker kill sqliteserver || bin/true'
ExecStartPre=/bin/bash \                                  #ExecStartPre定义了服务单元被启动之前运行的命令。为了确保容器在用户启动之前已被删除,这里使用了一个前置命令将其删除
-c '/usr/bin/docker rm -f sqliteserver || /bin/true'
ExecStartPre=/usr/bin/docker \
pull dockerinpractice/docker-compose-sqlite               #确保启动容器之前镜像已下载完成了
ExecStart=/usr/bin/docker run --name sqliteserver \       #ExecStart 定义了服务被启动之后运行的命令。这里值得注意的是,我们在另一个/bin/bash–c调用中包含了socat 命令,因为在ExecStart 这一行定义的命令是由systemd来运行的
-v /tmp/sqlitedbs/test:/opt/sqlite/db \
dockerinpractice/docker-compose-sqlite /bin/bash -c \
'socat TCP-L:12345,fork,reuseaddr \
EXEC:"sqlite3 /opt/sqlite/db",pty'
ExecStop=/usr/bin/docker rm -f sqliteserver               #ExecStop定义了服务停止之后运行的命令
[Install]
WantedBy=multi-user.target

image.gif

如下代码列出的是sqliteproxy服务。这里最大的区别在于,代理服务依赖于刚刚定义的服务器进程,而服务端进程又依赖于Docker服务。

[Unit]
Description=SQLite Docker Proxy 
After=sqliteserver.service                                     #该代理单元必须在前面定义的sqliteserver服务之后运行
Requires=sqliteserver.service                                  #启动该代理之前要求服务器实例在运行
[Service]
Restart=always
ExecStartPre=/bin/bash -c '/usr/bin/docker kill sqliteproxy || /bin/true' 
ExecStartPre=/bin/bash -c '/usr/bin/docker rm -f sqliteproxy || /bin/true' ExecStartPre=/usr/bin/docker pull dockerinpractice/docker-compose-sqlite 
ExecStart=/usr/bin/docker run --name sqliteproxy \
-p 12346:12346 --link sqliteserver:sqliteserver \ 
dockerinpractice/docker-compose-sqlite /bin/bash \
-c 'socat TCP-L:12346,fork,reuseaddr TCP:sqliteserver:12345'   #该命令用于运行容器
ExecStop=/usr/bin/docker rm -f sqliteproxy
[Install]
WantedBy=multi-user.target

image.gif

通过这两个配置文件,我们为在systemd控制下安装和运行SQLite服务奠定了基础。现在我们可以启用这些服务了:

$ sudo systemctl enable /etc/systemd/system/sqliteserver.service ln -s '/etc/systemd/system/sqliteserver.service' \ 
'/etc/systemd/system/multi-user.target.wants/sqliteserver.service' 
$ sudo systemctl enable /etc/systemd/system/sqliteproxy.service
ln -s '/etc/systemd/system/sqliteproxy.service' \ 
'/etc/systemd/system/multi-user.target.wants/sqliteproxy.service'

image.gif

然后启动它们:

$ sudo systemctl start sqlit\eproxy 
$ telnet localhost 12346
[vagrant@centos ~]$ telnet localhost 12346 
Trying ::1...
Connected to localhost.
Escape character is '^]'.
SQLite version 3.8.2 2013-12-06 14:53:30
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> select * from t1;
select * from t1;
test

image.gif


值得注意的是,sqliteproxy服务依赖于sqliteserver服务的运行。只需要启动sqliteproxy服务即可,其他依赖的服务会自动启动。

👑👑👑结束语👑👑👑

image.gif

目录
相关文章
|
5天前
|
数据库 Docker 容器
docker容器为啥会开机自启动
通过配置适当的重启策略,Docker容器可以在主机系统重启后自动启动。这对于保持关键服务的高可用性和自动恢复能力非常有用。选择适合的重启策略(如 `always`或 `unless-stopped`),可以确保应用程序在各种情况下保持运行。理解并配置这些策略是确保Docker容器化应用可靠性的关键。
150 93
|
7天前
|
Ubuntu NoSQL Linux
《docker基础篇:3.Docker常用命令》包括帮助启动类命令、镜像命令、有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)、容器命令、小总结
《docker基础篇:3.Docker常用命令》包括帮助启动类命令、镜像命令、有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)、容器命令、小总结
65 6
《docker基础篇:3.Docker常用命令》包括帮助启动类命令、镜像命令、有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)、容器命令、小总结
|
18天前
|
搜索推荐 安全 数据安全/隐私保护
7 个最能提高生产力的 Docker 容器
7 个最能提高生产力的 Docker 容器
98 35
|
6天前
|
数据库 Docker 容器
docker容器为啥会开机自启动
通过配置适当的重启策略,Docker容器可以在主机系统重启后自动启动。这对于保持关键服务的高可用性和自动恢复能力非常有用。选择适合的重启策略(如 `always`或 `unless-stopped`),可以确保应用程序在各种情况下保持运行。理解并配置这些策略是确保Docker容器化应用可靠性的关键。
33 17
|
17天前
|
Ubuntu Linux 开发工具
docker 是什么?docker初认识之如何部署docker-优雅草后续将会把产品发布部署至docker容器中-因此会出相关系列文章-优雅草央千澈
Docker 是一个开源的容器化平台,允许开发者将应用程序及其依赖项打包成标准化单元(容器),确保在任何支持 Docker 的操作系统上一致运行。容器共享主机内核,提供轻量级、高效的执行环境。本文介绍如何在 Ubuntu 上安装 Docker,并通过简单步骤验证安装成功。后续文章将探讨使用 Docker 部署开源项目。优雅草央千澈 源、安装 Docker 包、验证安装 - 适用场景:开发、测试、生产环境 通过以上步骤,您可以在 Ubuntu 系统上成功安装并运行 Docker,为后续的应用部署打下基础。
docker 是什么?docker初认识之如何部署docker-优雅草后续将会把产品发布部署至docker容器中-因此会出相关系列文章-优雅草央千澈
|
6天前
|
运维 Java 虚拟化
《docker基础篇:1.Docker简介》,包括Docker是什么、容器与虚拟机比较、能干嘛、去哪下
《docker基础篇:1.Docker简介》,包括Docker是什么、容器与虚拟机比较、能干嘛、去哪下
61 12
|
7天前
|
Kubernetes Linux 虚拟化
入门级容器技术解析:Docker和K8s的区别与关系
本文介绍了容器技术的发展历程及其重要组成部分Docker和Kubernetes。从传统物理机到虚拟机,再到容器化,每一步都旨在更高效地利用服务器资源并简化应用部署。容器技术通过隔离环境、减少依赖冲突和提高可移植性,解决了传统部署方式中的诸多问题。Docker作为容器化平台,专注于创建和管理容器;而Kubernetes则是一个强大的容器编排系统,用于自动化部署、扩展和管理容器化应用。两者相辅相成,共同推动了现代云原生应用的快速发展。
56 11
|
23天前
|
存储 Kubernetes 开发者
容器化时代的领航者:Docker 和 Kubernetes 云原生时代的黄金搭档
Docker 是一种开源的应用容器引擎,允许开发者将应用程序及其依赖打包成可移植的镜像,并在任何支持 Docker 的平台上运行。其核心概念包括镜像、容器和仓库。镜像是只读的文件系统,容器是镜像的运行实例,仓库用于存储和分发镜像。Kubernetes(k8s)则是容器集群管理系统,提供自动化部署、扩展和维护等功能,支持服务发现、负载均衡、自动伸缩等特性。两者结合使用,可以实现高效的容器化应用管理和运维。Docker 主要用于单主机上的容器管理,而 Kubernetes 则专注于跨多主机的容器编排与调度。尽管 k8s 逐渐减少了对 Docker 作为容器运行时的支持,但 Doc
121 5
容器化时代的领航者:Docker 和 Kubernetes 云原生时代的黄金搭档
|
15天前
|
存储 人工智能 调度
容器服务:智算时代云原生操作系统及月之暗面Kimi、深势科技实践分享
容器技术已经发展成为云计算操作系统的关键组成部分,向下高效调度多样化异构算力,向上提供统一编程接口,支持多样化工作负载。阿里云容器服务在2024年巴黎奥运会中提供了稳定高效的云上支持,实现了子弹时间特效等创新应用。此外,容器技术还带来了弹性、普惠的计算能力升级,如每分钟创建1万Pod和秒级CPU资源热变配,以及针对大数据与AI应用的弹性临时盘和跨可用区云盘等高性能存储解决方案。智能运维方面,推出了即时弹性节点池、智能应用弹性策略和可信赖集群托管运维等功能,进一步简化了集群管理和优化了资源利用率。
|
13天前
|
监控 安全 Cloud Native
阿里云容器服务&云安全中心团队荣获信通院“云原生安全标杆案例”奖
2024年12月24日,阿里云容器服务团队与云安全中心团队获得中国信息通信研究院「云原生安全标杆案例」奖。