add ulimit support for kolla_docker
By default, docker containers inherit ulimit from limits of docker deamon. On CentOS 7, docker daemon default NOFILE is 1048576. It can found in /usr/lib/systemd/system/docker.service. The big limit will cause many problem. we should control it in production environment. Change-Id: Iab962446a94ef092977728259d9818b86cfa7f68
This commit is contained in:
parent
cd0d8cca9b
commit
3d3f5f1613
@ -474,7 +474,8 @@ class DockerWorker(object):
|
||||
'memswap_limit': 'MemorySwap', 'cpu_period': 'CpuPeriod',
|
||||
'cpu_quota': 'CpuQuota', 'cpu_shares': 'CpuShares',
|
||||
'cpuset_cpus': 'CpusetCpus', 'cpuset_mems': 'CpusetMems',
|
||||
'kernel_memory': 'KernelMemory', 'blkio_weight': 'BlkioWeight'}
|
||||
'kernel_memory': 'KernelMemory', 'blkio_weight': 'BlkioWeight',
|
||||
'ulimits': 'Ulimits'}
|
||||
unsupported = set(new_dimensions.keys()) - \
|
||||
set(dimension_map.keys())
|
||||
if unsupported:
|
||||
@ -486,13 +487,29 @@ class DockerWorker(object):
|
||||
# NOTE(mgoddard): If a resource has been explicitly requested,
|
||||
# check for a match. Otherwise, ensure is is set to the default.
|
||||
if key1 in new_dimensions:
|
||||
if new_dimensions[key1] != current_dimensions[key2]:
|
||||
if key1 == 'ulimits':
|
||||
if self.compare_ulimits(new_dimensions[key1],
|
||||
current_dimensions[key2]):
|
||||
return True
|
||||
elif new_dimensions[key1] != current_dimensions[key2]:
|
||||
return True
|
||||
elif current_dimensions[key2]:
|
||||
# The default values of all currently supported resources are
|
||||
# '' or 0 - both falsey.
|
||||
return True
|
||||
|
||||
def compare_ulimits(self, new_ulimits, current_ulimits):
|
||||
# The new_ulimits is dict, we need make it to a list of Ulimit
|
||||
# instance.
|
||||
new_ulimits = self.build_ulimits(new_ulimits)
|
||||
|
||||
def key(ulimit):
|
||||
return ulimit['Name']
|
||||
|
||||
if current_ulimits is None:
|
||||
current_ulimits = []
|
||||
return sorted(new_ulimits, key=key) != sorted(current_ulimits, key=key)
|
||||
|
||||
def compare_command(self, container_info):
|
||||
new_command = self.params.get('command')
|
||||
if new_command is not None:
|
||||
@ -606,6 +623,40 @@ class DockerWorker(object):
|
||||
|
||||
return vol_list, vol_dict
|
||||
|
||||
def parse_dimensions(self, dimensions):
|
||||
# When the data object contains types such as
|
||||
# docker.types.Ulimit, Ansible will fail when these are
|
||||
# returned via exit_json or fail_json. HostConfig is derived from dict,
|
||||
# but its constructor requires additional arguments.
|
||||
# to avoid that, here do copy the dimensions and return a new one.
|
||||
dimensions = dimensions.copy()
|
||||
|
||||
supported = {'cpu_period', 'cpu_quota', 'cpu_shares',
|
||||
'cpuset_cpus', 'cpuset_mems', 'mem_limit',
|
||||
'mem_reservation', 'memswap_limit',
|
||||
'kernel_memory', 'blkio_weight', 'ulimits'}
|
||||
unsupported = set(dimensions) - supported
|
||||
if unsupported:
|
||||
self.module.exit_json(failed=True,
|
||||
msg=repr("Unsupported dimensions"),
|
||||
unsupported_dimensions=unsupported)
|
||||
|
||||
ulimits = dimensions.get('ulimits')
|
||||
if ulimits:
|
||||
dimensions['ulimits'] = self.build_ulimits(ulimits)
|
||||
|
||||
return dimensions
|
||||
|
||||
def build_ulimits(self, ulimits):
|
||||
ulimits_opt = []
|
||||
for key, value in ulimits.items():
|
||||
soft = value.get('soft')
|
||||
hard = value.get('hard')
|
||||
ulimits_opt.append(docker.types.Ulimit(name=key,
|
||||
soft=soft,
|
||||
hard=hard))
|
||||
return ulimits_opt
|
||||
|
||||
def build_host_config(self, binds):
|
||||
options = {
|
||||
'network_mode': 'host',
|
||||
@ -617,17 +668,11 @@ class DockerWorker(object):
|
||||
'volumes_from': self.params.get('volumes_from')
|
||||
}
|
||||
|
||||
if self.params.get('dimensions'):
|
||||
supported = {'cpu_period', 'cpu_quota', 'cpu_shares',
|
||||
'cpuset_cpus', 'cpuset_mems', 'mem_limit',
|
||||
'mem_reservation', 'memswap_limit',
|
||||
'kernel_memory', 'blkio_weight'}
|
||||
unsupported = set(self.params.get('dimensions')) - supported
|
||||
if unsupported:
|
||||
self.module.exit_json(failed=True,
|
||||
msg=repr("Unsupported dimensions"),
|
||||
unsupported_dimensions=unsupported)
|
||||
options.update(self.params.get('dimensions'))
|
||||
dimensions = self.params.get('dimensions')
|
||||
|
||||
if dimensions:
|
||||
dimensions = self.parse_dimensions(dimensions)
|
||||
options.update(dimensions)
|
||||
|
||||
if self.params.get('restart_policy') in ['on-failure',
|
||||
'always',
|
||||
@ -940,5 +985,6 @@ def main():
|
||||
module.fail_json(changed=True, msg=repr(traceback.format_exc()),
|
||||
**dw.result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@ -27,6 +27,7 @@ The resources currently supported by Kolla Ansible are:
|
||||
memswap_limit
|
||||
kernel_memory
|
||||
blkio_weight
|
||||
ulimits
|
||||
|
||||
Pre-deployment Configuration
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -67,6 +68,9 @@ Dimensions are defined as a mapping from a Docker resource name
|
||||
* - cpuset_mems
|
||||
- String
|
||||
- ''(Empty String)
|
||||
* - ulimits
|
||||
- Dict
|
||||
- {}
|
||||
|
||||
|
||||
The variable ``default_container_dimensions`` sets the default dimensions
|
||||
@ -96,6 +100,23 @@ options section in ``/etc/kolla/globals.yml``:
|
||||
nova_libvirt_dimensions:
|
||||
cpuset_cpus: "2"
|
||||
|
||||
How to config ulimits in kolla
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
<container_name>_dimensions:
|
||||
ulimits:
|
||||
nofile:
|
||||
soft: 131072
|
||||
hard: 131072
|
||||
fsize:
|
||||
soft: 131072
|
||||
hard: 131072
|
||||
|
||||
A list of valid names can be found [here]
|
||||
(https://github.com/docker/go-units/blob/d4a9b9617350c034730bc5051c605919943080bf/ulimit.go#L46-L63)
|
||||
|
||||
Deployment
|
||||
~~~~~~~~~~
|
||||
|
||||
|
@ -142,6 +142,7 @@ kolla_internal_vip_address: "10.10.10.254"
|
||||
# mem_reservation:
|
||||
# memswap_limit:
|
||||
# kernel_memory:
|
||||
# ulimits:
|
||||
|
||||
|
||||
#############
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Add ulimit support for kolla_docker which provides ability
|
||||
of modify docker ulimits。
|
@ -23,6 +23,7 @@ try:
|
||||
except ImportError:
|
||||
import mock
|
||||
from docker import errors as docker_error
|
||||
from docker.types import Ulimit
|
||||
from oslotest import base
|
||||
|
||||
this_dir = os.path.dirname(sys.modules[__name__].__file__)
|
||||
@ -904,7 +905,8 @@ class TestAttrComp(base.BaseTestCase):
|
||||
container_info['HostConfig'] = {
|
||||
'CpuPeriod': 0, 'KernelMemory': 0, 'Memory': 0, 'CpuQuota': 0,
|
||||
'CpusetCpus': '', 'CpuShares': 0, 'BlkioWeight': 0,
|
||||
'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 0}
|
||||
'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 0,
|
||||
'Ulimits': []}
|
||||
self.dw = get_DockerWorker(self.fake_data['params'])
|
||||
self.assertTrue(self.dw.compare_dimensions(container_info))
|
||||
|
||||
@ -915,7 +917,8 @@ class TestAttrComp(base.BaseTestCase):
|
||||
container_info['HostConfig'] = {
|
||||
'CpuPeriod': 0, 'KernelMemory': 0, 'Memory': 0, 'CpuQuota': 0,
|
||||
'CpusetCpus': '', 'CpuShares': 0, 'BlkioWeight': 10,
|
||||
'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 0}
|
||||
'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 0,
|
||||
'Ulimits': []}
|
||||
self.dw = get_DockerWorker(self.fake_data['params'])
|
||||
self.assertFalse(self.dw.compare_dimensions(container_info))
|
||||
|
||||
@ -926,7 +929,8 @@ class TestAttrComp(base.BaseTestCase):
|
||||
container_info['HostConfig'] = {
|
||||
'CpuPeriod': 0, 'KernelMemory': 0, 'Memory': 0, 'CpuQuota': 0,
|
||||
'CpusetCpus': '', 'CpuShares': 0, 'BlkioWeight': 0,
|
||||
'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 0}
|
||||
'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 0,
|
||||
'Ulimits': []}
|
||||
self.dw = get_DockerWorker(self.fake_data['params'])
|
||||
self.dw.compare_dimensions(container_info)
|
||||
self.dw.module.exit_json.assert_called_once_with(
|
||||
@ -939,7 +943,8 @@ class TestAttrComp(base.BaseTestCase):
|
||||
container_info['HostConfig'] = {
|
||||
'CpuPeriod': 0, 'KernelMemory': 0, 'Memory': 0, 'CpuQuota': 0,
|
||||
'CpusetCpus': '1', 'CpuShares': 0, 'BlkioWeight': 0,
|
||||
'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 0}
|
||||
'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 0,
|
||||
'Ulimits': []}
|
||||
self.dw = get_DockerWorker(self.fake_data['params'])
|
||||
self.assertTrue(self.dw.compare_dimensions(container_info))
|
||||
|
||||
@ -954,7 +959,8 @@ class TestAttrComp(base.BaseTestCase):
|
||||
container_info['HostConfig'] = {
|
||||
'CpuPeriod': 0, 'KernelMemory': 0, 'Memory': 10, 'CpuQuota': 0,
|
||||
'CpusetCpus': '', 'CpuShares': 0, 'BlkioWeight': 0,
|
||||
'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 10}
|
||||
'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 10,
|
||||
'Ulimits': []}
|
||||
self.dw = get_DockerWorker(self.fake_data['params'])
|
||||
self.assertTrue(self.dw.compare_dimensions(container_info))
|
||||
|
||||
@ -969,7 +975,8 @@ class TestAttrComp(base.BaseTestCase):
|
||||
container_info['HostConfig'] = {
|
||||
'CpuPeriod': 0, 'KernelMemory': 0, 'Memory': 0, 'CpuQuota': 0,
|
||||
'CpusetCpus': '', 'CpuShares': 0, 'BlkioWeight': 0,
|
||||
'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 0}
|
||||
'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 0,
|
||||
'Ulimits': []}
|
||||
self.dw = get_DockerWorker(self.fake_data['params'])
|
||||
self.assertFalse(self.dw.compare_dimensions(container_info))
|
||||
|
||||
@ -977,3 +984,29 @@ class TestAttrComp(base.BaseTestCase):
|
||||
container_info = {'State': dict(Status='running')}
|
||||
self.dw = get_DockerWorker({'state': 'exited'})
|
||||
self.assertTrue(self.dw.compare_container_state(container_info))
|
||||
|
||||
def test_compare_ulimits_pos(self):
|
||||
self.fake_data['params']['dimensions'] = {
|
||||
'ulimits': {'nofile': {'soft': 131072, 'hard': 131072}}}
|
||||
container_info = dict()
|
||||
container_info['HostConfig'] = {
|
||||
'CpuPeriod': 0, 'KernelMemory': 0, 'Memory': 0, 'CpuQuota': 0,
|
||||
'CpusetCpus': '', 'CpuShares': 0, 'BlkioWeight': 0,
|
||||
'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 0,
|
||||
'Ulimits': []}
|
||||
self.dw = get_DockerWorker(self.fake_data['params'])
|
||||
self.assertTrue(self.dw.compare_dimensions(container_info))
|
||||
|
||||
def test_compare_ulimits_neg(self):
|
||||
self.fake_data['params']['dimensions'] = {
|
||||
'ulimits': {'nofile': {'soft': 131072, 'hard': 131072}}}
|
||||
ulimits_nofile = Ulimit(name='nofile',
|
||||
soft=131072, hard=131072)
|
||||
container_info = dict()
|
||||
container_info['HostConfig'] = {
|
||||
'CpuPeriod': 0, 'KernelMemory': 0, 'Memory': 0, 'CpuQuota': 0,
|
||||
'CpusetCpus': '', 'CpuShares': 0, 'BlkioWeight': 0,
|
||||
'CpusetMems': '', 'MemorySwap': 0, 'MemoryReservation': 0,
|
||||
'Ulimits': [ulimits_nofile]}
|
||||
self.dw = get_DockerWorker(self.fake_data['params'])
|
||||
self.assertFalse(self.dw.compare_dimensions(container_info))
|
||||
|
Loading…
Reference in New Issue
Block a user