Skip to content

Adds support to run lightweight kubernetes testcontainer using k3s #313

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Nov 28, 2023
1 change: 1 addition & 0 deletions k3s/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
url="https://github.com/testcontainers/testcontainers-python",
install_requires=[
"testcontainers-core",
"kubernetes"
],
python_requires=">=3.7",
)
18 changes: 11 additions & 7 deletions k3s/testcontainers/k3s/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ class K3SContainer(DockerContainer):
>>> from testcontainers.k3s import K3SContainer

>>> with K3SContainer() as k3s:
... config_yaml = k3s.config_yaml()
... config.load_kube_config_from_dict(yaml.safe_load(k3s.config_yaml()))
... pod = client.CoreV1Api().list_pod_for_all_namespaces(limit=1)
... assert len(pod.items) > 0, "Unable to get running nodes from k3s cluster"
"""

KUBE_SECURE_PORT = 6443
Expand All @@ -38,8 +40,7 @@ class K3SContainer(DockerContainer):
def __init__(self, image="rancher/k3s:latest", **kwargs) -> None:
super(K3SContainer, self).__init__(image, **kwargs)
self.with_exposed_ports(self.KUBE_SECURE_PORT, self.RANCHER_WEBHOOK_PORT)
self.with_env("K3S_URL",
'https://localhost:{}'.format(self.KUBE_SECURE_PORT))
self.with_env("K3S_URL", f'https://{self.get_container_host_ip()}:{self.KUBE_SECURE_PORT}')
self.with_command("server --disable traefik --tls-san=" + self.get_container_host_ip())
self.with_kwargs(privileged=True, tmpfs={"/run": "", "/var/run": ""})
self.with_volume_mapping("/sys/fs/cgroup", "/sys/fs/cgroup", "rw")
Expand All @@ -53,8 +54,11 @@ def start(self) -> "K3SContainer":
return self

def config_yaml(self) -> str:
output = self.get_wrapped_container().exec_run(['cat', '/etc/rancher/k3s/k3s.yaml'])
config_yaml = output.output.decode('utf-8') \
.replace('https://127.0.0.1:{}'.format(self.KUBE_SECURE_PORT), 'https://localhost:{}'
.format(self.get_exposed_port(self.KUBE_SECURE_PORT)))
"""This function returns the kubernetes config yaml which can be used
to initialise python client
"""
execution = self.get_wrapped_container().exec_run(['cat', '/etc/rancher/k3s/k3s.yaml'])
config_yaml = execution.output.decode('utf-8') \
.replace(f'https://127.0.0.1:{self.KUBE_SECURE_PORT}',
f'https://localhost:{self.get_exposed_port(self.KUBE_SECURE_PORT)}')
return config_yaml
10 changes: 6 additions & 4 deletions k3s/tests/test_k3s.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# The versions below were the current supported versions at time of writing (2022-08-11)
import yaml
from kubernetes import client, config

from testcontainers.k3s import K3SContainer


def test_docker_run_elasticsearch():
def test_docker_run_k3s():
with K3SContainer() as k3s:
exposed_port = k3s.get_exposed_port(k3s.KUBE_SECURE_PORT)
server_url_in_config_yaml = 'https://localhost:{}'.format(exposed_port)
assert server_url_in_config_yaml in k3s.config_yaml()
config.load_kube_config_from_dict(yaml.safe_load(k3s.config_yaml()))
pod = client.CoreV1Api().list_pod_for_all_namespaces(limit=1)
assert len(pod.items) > 0, "Unable to get running nodes from k3s cluster"
56 changes: 39 additions & 17 deletions requirements/3.10.txt
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ azure-core==1.26.3
# via azure-storage-blob
azure-storage-blob==12.15.0
# via testcontainers-azurite
babel==2.11.0
babel==2.12.1
# via sphinx
bcrypt==4.0.1
# via paramiko
Expand All @@ -106,6 +106,7 @@ cachetools==5.3.0
# via google-auth
certifi==2022.12.7
# via
# kubernetes
# minio
# opensearch-py
# requests
Expand All @@ -114,13 +115,13 @@ cffi==1.15.1
# via
# cryptography
# pynacl
charset-normalizer==3.0.1
charset-normalizer==3.1.0
# via requests
clickhouse-driver==0.2.5
# via testcontainers-clickhouse
codecov==2.1.12
# via -r requirements.in
coverage[toml]==7.2.0
coverage[toml]==7.2.1
# via
# codecov
# pytest-cov
Expand All @@ -132,6 +133,8 @@ cryptography==36.0.2
# secretstorage
cx-oracle==8.3.0
# via testcontainers-oracle
deprecation==2.1.0
# via python-keycloak
distro==1.8.0
# via docker-compose
dnspython==2.3.0
Expand Down Expand Up @@ -162,8 +165,10 @@ flake8==3.7.9
# via -r requirements.in
google-api-core[grpc]==2.11.0
# via google-cloud-pubsub
google-auth==2.16.1
# via google-api-core
google-auth==2.16.2
# via
# google-api-core
# kubernetes
google-cloud-pubsub==1.7.2
# via testcontainers-gcp
googleapis-common-protos[grpc]==1.58.0
Expand Down Expand Up @@ -213,6 +218,8 @@ kafka-python==2.0.2
# via testcontainers-kafka
keyring==23.13.1
# via twine
kubernetes==26.1.0
# via testcontainers-k3s
markdown-it-py==2.2.0
# via rich
markupsafe==2.1.2
Expand All @@ -223,16 +230,19 @@ mdurl==0.1.2
# via markdown-it-py
minio==7.1.13
# via testcontainers-minio
more-itertools==9.0.0
more-itertools==9.1.0
# via jaraco-classes
neo4j==5.5.0
neo4j==5.6.0
# via testcontainers-neo4j
opensearch-py==2.1.1
oauthlib==3.2.2
# via requests-oauthlib
opensearch-py==2.2.0
# via testcontainers-opensearch
outcome==1.2.0
# via trio
packaging==23.0
# via
# deprecation
# docker
# pytest
# sphinx
Expand Down Expand Up @@ -287,7 +297,7 @@ pyrsistent==0.19.3
# via jsonschema
pysocks==1.7.1
# via urllib3
pytest==7.2.1
pytest==7.2.2
# via
# -r requirements.in
# pytest-cov
Expand All @@ -296,22 +306,26 @@ pytest-cov==4.0.0
python-arango==7.5.7
# via testcontainers-arangodb
python-dateutil==2.8.2
# via pg8000
# via
# kubernetes
# opensearch-py
# pg8000
python-dotenv==0.21.1
# via docker-compose
python-jose==3.3.0
# via python-keycloak
python-keycloak==2.12.0
python-keycloak==2.13.2
# via testcontainers-keycloak
pytz==2022.7.1
# via
# babel
# clickhouse-driver
# neo4j
pytz-deprecation-shim==0.1.0.post0
# via tzlocal
pyyaml==5.4.1
# via docker-compose
# via
# docker-compose
# kubernetes
readme-renderer==37.3
# via twine
redis==4.5.1
Expand All @@ -323,20 +337,24 @@ requests==2.28.2
# docker
# docker-compose
# google-api-core
# kubernetes
# opensearch-py
# python-arango
# python-keycloak
# requests-oauthlib
# requests-toolbelt
# sphinx
# twine
requests-toolbelt==0.9.1
requests-oauthlib==1.3.1
# via kubernetes
requests-toolbelt==0.10.1
# via
# python-arango
# python-keycloak
# twine
rfc3986==2.0.0
# via twine
rich==13.3.1
rich==13.3.2
# via twine
rsa==4.9
# via
Expand All @@ -357,6 +375,8 @@ six==1.16.0
# google-auth
# isodate
# jsonschema
# kubernetes
# opensearch-py
# python-dateutil
# websocket-client
sniffio==1.3.0
Expand All @@ -379,7 +399,7 @@ sphinxcontrib-qthelp==1.0.3
# via sphinx
sphinxcontrib-serializinghtml==1.1.5
# via sphinx
sqlalchemy==2.0.4
sqlalchemy==2.0.5.post1
# via
# testcontainers-mssql
# testcontainers-mysql
Expand Down Expand Up @@ -411,6 +431,7 @@ tzlocal==4.2
urllib3[socks]==1.26.14
# via
# docker
# kubernetes
# minio
# opensearch-py
# python-arango
Expand All @@ -424,9 +445,10 @@ websocket-client==0.59.0
# via
# docker
# docker-compose
# kubernetes
wheel==0.38.4
# via -r requirements.in
wrapt==1.14.1
wrapt==1.15.0
# via testcontainers-core
wsproto==1.2.0
# via trio-websocket
Expand Down
Loading