内容简介:sonic业务进程都是运行在容器中的,那容器启动后是如何启动它的服务呢。要分析这个问题,首先要搞清楚容器构建过程。我们以docker-orchagent容器为例进行分析。sonic中的Dockerfile由Dockerfile.j2文件生成。
sonic容器swss启动过程
sonic业务进程都是运行在容器中的,那容器启动后是如何启动它的服务呢。
要分析这个问题,首先要搞清楚容器构建过程。我们以docker-orchagent容器为例进行分析。
Dockerfile文件
sonic中的Dockerfile由Dockerfile.j2文件生成。
docker-orchagent/Dockerfile.j2
FROM docker-config-engine ARG docker_container_name RUN [ -f /etc/rsyslog.conf ] && sed -ri "s/%syslogtag%/$docker_container_name\/%syslogtag%/;" /etc/rsyslog.conf ## Make apt-get non-interactive ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update RUN apt-get install -f -y ifupdown arping libdbus-1-3 libdaemon0 libjansson4 ## Install redis-tools dependencies ## TODO: implicitly install dependencies RUN apt-get -y install libjemalloc1 COPY \ {% for deb in docker_orchagent_debs.split(' ') -%} debs/{{ deb }}{{' '}} {%- endfor -%} debs/ RUN dpkg -i \ {% for deb in docker_orchagent_debs.split(' ') -%} debs/{{ deb }}{{' '}} {%- endfor %} ## Clean up RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y RUN rm -rf /debs COPY ["files/arp_update", "/usr/bin"] COPY ["enable_counters.py", "/usr/bin"] COPY ["start.sh", "orchagent.sh", "swssconfig.sh", "/usr/bin/"] COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] ## Copy all Jinja2 template files into the templates folder COPY ["*.j2", "/usr/share/sonic/templates/"] #程序的入口点 ENTRYPOINT ["/usr/bin/supervisord"]
从上面的配置来看,容器启动后制定的程序为:/usr/bin/supervisord
Host启动容器
Host是以swss服务形式启动docker-orchagent容器的,使用如下命令可以看出:
admin@sonic:~$ sudo config reload -y Running command: systemctl stop swss Running command: systemctl stop pmon Running command: systemctl stop teamd Running command: sonic-cfggen -j /etc/sonic/config_db.json --write-to-db Running command: systemctl restart hostname-config Running command: systemctl restart interfaces-config Running command: systemctl restart ntp-config Running command: systemctl restart rsyslog-config Running command: systemctl restart swss Running command: systemctl restart teamd Running command: systemctl restart pmon admin@sonic:~$
我们查看一下swss的service文件
admin@sonic:~$ cat /etc/systemd/system/swss.service
[Unit] Description=switch state service Requires=database.service updategraph.service After=database.service updategraph.service After=interfaces-config.service [Service] User=root # Wait for redis server start before database clean ExecStartPre=/bin/bash -c 'until [[ $(/usr/bin/docker exec database redis-cli ping | grep -c PONG) -gt 0 ]]; do sleep 1; done' ExecStartPre=/usr/bin/docker exec database redis-cli -n 0 FLUSHDB ExecStartPre=/usr/bin/docker exec database redis-cli -n 1 FLUSHDB ExecStartPre=/usr/bin/docker exec database redis-cli -n 2 FLUSHDB ExecStartPre=/usr/bin/docker exec database redis-cli -n 5 FLUSHDB ExecStartPre=/usr/bin/docker exec database redis-cli -n 6 FLUSHDB ExecStartPre=/usr/bin/swss.sh start ExecStartPre=/usr/bin/syncd.sh start ExecStart=/usr/bin/swss.sh attach ExecStop=/usr/bin/swss.sh stop ExecStopPost=/usr/bin/syncd.sh stop [Install] WantedBy=multi-user.target
可以看出swss服务的启动程序是/usr/bin/swss.sh attach。在启动该服务之前,需要执行如下命令:
# Wait for redis server start before database clean # 等待,直到 redis 可用,可用表示ping之后会返回PONG,那么grep -c PONG则为1大于0 ExecStartPre=/bin/bash -c 'until [[ $(/usr/bin/docker exec database redis-cli ping | grep -c PONG) -gt 0 ]]; do sleep 1; done' ExecStartPre=/usr/bin/docker exec database redis-cli -n 0 FLUSHDB ExecStartPre=/usr/bin/docker exec database redis-cli -n 1 FLUSHDB ExecStartPre=/usr/bin/docker exec database redis-cli -n 2 FLUSHDB ExecStartPre=/usr/bin/docker exec database redis-cli -n 5 FLUSHDB ExecStartPre=/usr/bin/docker exec database redis-cli -n 6 FLUSHDB ExecStartPre=/usr/bin/swss.sh start ExecStartPre=/usr/bin/syncd.sh start
会清空数据库0,1,2,5,6,不会清空4(config_db),即会保留配置。还会启动/usr/bin/swss.sh start 和/usr/bin/syncd.sh start。
我们看一下/usr/bin/swss.sh脚本
#!/bin/bash function getMountPoint() { echo $1 | python -c "import sys, json, os; mnts = [x for x in json.load(sys.stdin)[0]['Mounts'] if x['Destination'] == '/usr/share/sonic/hwsku']; print '' if len(mnts) == 0 else os.path.basename(mnts[0]['Source'])" 2>/dev/null } function postStartAction() { docker exec swss rm -f /ready # remove cruft if [[ -d /host/fast-reboot ]]; then test -e /host/fast-reboot/fdb.json && docker cp /host/fast-reboot/fdb.json swss:/ test -e /host/fast-reboot/arp.json && docker cp /host/fast-reboot/arp.json swss:/ test -e /host/fast-reboot/default_routes.json && docker cp /host/fast-reboot/default_routes.json swss:/ rm -fr /host/fast-reboot fi docker exec swss touch /ready # signal swssconfig.sh to go } # Obtain our platform as we will mount directories with these names in each docker PLATFORM=`sonic-cfggen -H -v DEVICE_METADATA.localhost.platform` # Obtain our HWSKU as we will mount directories with these names in each docker HWSKU=`sonic-cfggen -d -v 'DEVICE_METADATA["localhost"]["hwsku"]'` #启动容器 start() { DOCKERCHECK=`docker inspect --type container swss 2>/dev/null` if [ "$?" -eq "0" ]; then DOCKERMOUNT=`getMountPoint "$DOCKERCHECK"` if [ "$DOCKERMOUNT" == "$HWSKU" ]; then echo "Starting existing swss container with HWSKU $HWSKU" docker start swss postStartAction exit 0 fi # docker created with a different HWSKU, remove and recreate echo "Removing obsolete swss container with HWSKU $DOCKERMOUNT" docker rm -f swss fi echo "Starting new swss container with HWSKU $HWSKU" docker run -d --net=host --privileged -t -v /etc/network/interfaces:/etc/network/interfaces:ro -v /etc/network/interfaces.d/:/etc/network/interfaces.d/:ro -v /host/machine.conf:/host/machine.conf:ro -v /etc/sonic:/etc/sonic:ro -v /var/log/swss:/var/log/swss:rw \ --log-opt max-size=2M --log-opt max-file=5 \ -v /var/run/redis:/var/run/redis:rw \ -v /usr/share/sonic/device/$PLATFORM:/usr/share/sonic/platform:ro \ -v /usr/share/sonic/device/$PLATFORM/$HWSKU:/usr/share/sonic/hwsku:ro \ --tmpfs /tmp \ --tmpfs /var/tmp \ --name=swss docker-orchagent-bfn:latest || { echo "Failed to docker run" >&1 exit 4 } postStartAction } attach() { docker attach --no-stdin swss } stop() { docker stop swss } case "$1" in start|stop|attach) $1 ;; *) echo "Usage: $0 {start|stop|attach}" exit 1 ;; esac
从上面的脚本可以看出,Host使用如下命令启动容器:
docker run -d --net=host --privileged -t -v /etc/network/interfaces:/etc/network/interfaces:ro -v /etc/network/interfaces.d/:/etc/network/interfaces.d/:ro -v /host/machine.conf:/host/machine.conf:ro -v /etc/sonic:/etc/sonic:ro -v /var/log/swss:/var/log/swss:rw \ --log-opt max-size=2M --log-opt max-file=5 \ -v /var/run/redis:/var/run/redis:rw \ -v /usr/share/sonic/device/$PLATFORM:/usr/share/sonic/platform:ro \ -v /usr/share/sonic/device/$PLATFORM/$HWSKU:/usr/share/sonic/hwsku:ro \ --tmpfs /tmp \ --tmpfs /var/tmp \ --name=swss docker-orchagent-bfn:latest
-
-d, --detach Run container in background and print container ID
我们单独的使用
run
只会启动容器,他会立即启动,相应然后就自动消失。你在这个时候使用exec
命令已经太迟了。所以,当我们启动容器的时候一定要加上
--detach或者-d
来保持容器在后台持续运行。 - --net=host 与host共享网络命名空间
- --privileged Give extended privileges to this container 使用该参数,container内的root拥有真正的root权限
- -v挂在host的一些目录到容器中。
- --name=swss 容器名字为swss
- docker-orchagent-bfn:latest 使用docker-orchagent-bfn:latest
命令没有携带CMD。
容器运行入口点
从Dockerfile.j2文件可以看出文件的入口点为ENTRYPOINT ["/usr/bin/supervisord"],使用supervisord进行进程监控,我们看一下supervisord的配置文件
进入swss容器后,我们查看启动了多少个进程。
root@switch:/# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 09:48 ? 00:00:01 /usr/bin/python /usr/bin/supervisord root 20 1 0 09:48 ? 00:00:00 /usr/bin/watcherd root 42 1 0 09:48 ? 00:00:00 /usr/sbin/rsyslogd -n root 47 1 0 09:48 ? 00:00:00 /usr/bin/orchagent -d /var/log/swss -b 8192 -m 00:90:fb:60:e2:8b root 59 1 1 09:48 ? 00:00:23 /usr/bin/portsyncd -p /usr/share/sonic/hwsku/port_config.ini root 62 1 0 09:48 ? 00:00:00 /usr/bin/intfsyncd root 65 1 0 09:48 ? 00:00:00 /usr/bin/neighsyncd root 77 1 0 09:49 ? 00:00:00 /usr/bin/vlanmgrd root 94 1 0 09:49 ? 00:00:00 /usr/bin/intfmgrd root 102 1 0 09:49 ? 00:00:00 /usr/bin/buffermgrd -l /usr/share/sonic/hwsku/pg_profile_lookup.ini root 112 1 0 09:49 ? 00:00:00 /bin/bash /usr/bin/arp_update root 335 112 0 10:24 ? 00:00:00 sleep 300 root 344 0 1 10:25 ? 00:00:00 bash root 349 344 0 10:25 ? 00:00:00 ps -ef root@switch:/#
上面的结果/usr/bin/python /usr/bin/supervisord可以看出,supervisord启动的时候没有指定配置文件,那么其使用的是默认配置文件/etc/supervisor/supervisord.conf:
; supervisor config file [unix_http_server] file=/var/run/supervisor.sock ; (the path to the socket file) chmod=0700 ; sockef file mode (default 0700) username=dummy password=dummy [supervisord] logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) childlogdir=/var/log/supervisor ; ('AUTO' child log dir, default $TEMP) user=root ; the below section must remain in the config file for RPC ; (supervisorctl/web interface) to work, additional interfaces may be ; added by defining them in separate rpcinterface: sections [rpcinterface:supervisor] supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface [supervisorctl] serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL for a unix socket username=dummy password=dummy ; The [include] section can just contain the "files" setting. This ; setting can list multiple files (separated by whitespace or ; newlines). It can also contain wildcards. The filenames are ; interpreted as relative to this file. Included files *cannot* ; include files themselves. [include] files = /etc/supervisor/conf.d/*.conf
查看子配置文件files = /etc/supervisor/conf.d/*.conf
/etc/supervisor/conf.d/目录下只有一个文件supervisord.conf:
[supervisord] logfile_maxbytes=1MB logfile_backups=2 nodaemon=true #运行start.sh,优先级为1 [program:start.sh] command=/usr/bin/start.sh priority=1 autostart=true autorestart=false stdout_logfile=syslog stderr_logfile=syslog #rsyslogd,优先级为2 [program:rsyslogd] command=/usr/sbin/rsyslogd -n priority=2 autostart=false autorestart=false stdout_logfile=syslog stderr_logfile=syslog #rsyslogd,优先级为2 [program:orchagent] command=/usr/bin/orchagent.sh priority=3 autostart=false autorestart=false stdout_logfile=syslog stderr_logfile=syslog #rsyslogd,优先级为2 [program:portsyncd] command=/usr/bin/portsyncd -p /usr/share/sonic/hwsku/port_config.ini priority=4 autostart=false autorestart=false stdout_logfile=syslog stderr_logfile=syslog #intfsyncd,优先级为2 [program:intfsyncd] command=/usr/bin/intfsyncd priority=5 autostart=false autorestart=false stdout_logfile=syslog stderr_logfile=syslog #neighsyncd,优先级为6 [program:neighsyncd] command=/usr/bin/neighsyncd priority=6 autostart=false autorestart=false stdout_logfile=syslog stderr_logfile=syslog #swssconfig.sh,优先级为7 [program:swssconfig] command=/usr/bin/swssconfig.sh priority=7 autostart=false autorestart=unexpected startretries=0 stdout_logfile=syslog stderr_logfile=syslog #arp_update,优先级为8 [program:arp_update] command=/usr/bin/arp_update priority=8 autostart=false autorestart=unexpected stdout_logfile=syslog stderr_logfile=syslog #vlanmgrd,优先级为9 [program:vlanmgrd] command=/usr/bin/vlanmgrd priority=9 autostart=false autorestart=false stdout_logfile=syslog stderr_logfile=syslog [program:intfmgrd] command=/usr/bin/intfmgrd priority=10 autostart=false autorestart=false stdout_logfile=syslog stderr_logfile=syslog [program:buffermgrd] command=/usr/bin/buffermgrd -l /usr/share/sonic/hwsku/pg_profile_lookup.ini priority=10 autostart=false autorestart=false stdout_logfile=syslog stderr_logfile=syslog [program:enable_counters] command=/usr/bin/enable_counters.py priority=11 autostart=false autorestart=false stdout_logfile=syslog stderr_logfile=syslog [eventlistener:mylistener] command=/usr/bin/watcherd events=PROCESS_STATE
start.sh
#!/usr/bin/env bash mkdir -p /etc/swss/config.d/ sonic-cfggen -d -t /usr/share/sonic/templates/switch.json.j2 > /etc/swss/config.d/switch.json sonic-cfggen -d -t /usr/share/sonic/templates/ipinip.json.j2 > /etc/swss/config.d/ipinip.json sonic-cfggen -d -t /usr/share/sonic/templates/ports.json.j2 > /etc/swss/config.d/ports.json export platform=`sonic-cfggen -H -v DEVICE_METADATA.localhost.platform` rm -f /var/run/rsyslogd.pid supervisorctl start rsyslogd supervisorctl start orchagent supervisorctl start portsyncd supervisorctl start intfsyncd supervisorctl start neighsyncd supervisorctl start swssconfig supervisorctl start vlanmgrd supervisorctl start intfmgrd supervisorctl start buffermgrd supervisorctl start enable_counters # Start arp_update when VLAN exists VLAN=`sonic-cfggen -d -v 'VLAN.keys() | join(" ") if VLAN'` if [ "$VLAN" != "" ]; then supervisorctl start arp_update fi
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 浅析Spring Framework框架容器启动过程
- spring源码之IOC容器资源定位过程
- Spring源码分析专题 —— IOC容器启动过程(下篇)
- Spring源码分析专题 —— IOC容器启动过程(中篇)
- 容器监控利器 - prometheus在生产落地过程中的思考
- 存储过程 – 重新编译后,存储过程运行得很快
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
算法设计与分析基础
Anany Levitin / 清华大学出版社 / 2007-11 / 59.00元
作者基于丰富的教学经验,开发了一套对算法进行分类的新方法。这套方法站在通用问题求解策略的高度,能对现有的大多数算法进行准确分类,从而使读者能够沿着一条清晰的、一致的、连贯的思路来探索算法设计与分析这一迷人领域。本书作为第2版,相对第1版增加了新的习题,还增加了“迭代改进”一章,使得原来的分类方法更加完善。 本书十分适合作为算法设计和分析的基础教材,也适合任何有兴趣探究算法奥秘的读者使用,只要......一起来看看 《算法设计与分析基础》 这本书的介绍吧!