stx: login to Dockerhub within k8s
Docker hub sometimes refuses to serve requests due to rate limits on anonymous pulls. We already support an option to login to Docker hub before pulling or building environment containers. However, this has no effect for images pulled by k8s itself, via a helm chart reference, eg for the nginx container. This patch adds a similar option: "stx start --use-dockerhub-cred": * creates a k8s secret with Docker hub credentials extracted from the calling user's $HOME/.docker/config.json * inserts this secret into the helm chart when starting This option is now used when "stx-init-env" is called with the "--dockerhub-login" option. TESTS ======================= * Use "stx control start --use-dockerhub-cred" and inspect the installed helm release to make sure the secret has been created and passed on to the chart * Using a slightly modified chart that refers to a private image, not accessible to anonymous users: - make sure k8s image pull fails without the new option - make sure k8s image pull succeeds with the new option * Delete the profile and re-create the environment with and without the login option * Make sure the secret gets deleted by "stx control stop" * Use "stx-init-env" with and without "--dockerhub-login" and make sure the helm chart is installed correctly Change-Id: I4c6962ad82e659005b4b7ea840c1ca709c05c60e Signed-off-by: Davlet Panech <davlet.panech@windriver.com>
This commit is contained in:
parent
09144c05d6
commit
bce548b9bc
@ -83,6 +83,7 @@ START_PODS=1
|
||||
RESET_SOFT=0
|
||||
RESET_HARD=0
|
||||
ASSUME_YES=0
|
||||
STX_START_OPTS=
|
||||
|
||||
COREUTILS_DOCKER_IMAGE="debian:bookworm-20240130-slim"
|
||||
|
||||
@ -238,7 +239,7 @@ stx_stop() {
|
||||
|
||||
stx_start() {
|
||||
stx config --upgrade || exit 1
|
||||
stx control start --wait || exit 1
|
||||
stx control start --wait $STX_START_OPTS || exit 1
|
||||
}
|
||||
|
||||
#
|
||||
@ -710,6 +711,10 @@ elif [[ $RESTART_MINIKUBE -eq 1 ]] ; then
|
||||
warn "--restart-minikube is only supported on minikube platform -- ignoring"
|
||||
fi
|
||||
|
||||
if [[ "$DOCKERHUB_LOGIN" -eq 1 ]] ; then
|
||||
STX_START_OPTS+=" --use-dockerhub-cred"
|
||||
fi
|
||||
|
||||
# Workaround: Wait for Minikube network to stabilize before building images
|
||||
sleep 10
|
||||
|
||||
|
@ -13,7 +13,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from stx import utils # pylint: disable=E0611
|
||||
import subprocess
|
||||
import tempfile
|
||||
@ -115,6 +118,87 @@ class KubeHelper(object):
|
||||
|
||||
return podname
|
||||
|
||||
def __get_docker_cred_secret_name(self):
|
||||
project_name = re.sub(r'[^a-z0-9-]', r'-',
|
||||
self.config.get('project', 'name').lower())
|
||||
return project_name + '-dockerconfigjson'
|
||||
|
||||
def try_create_docker_cred_secret(self):
|
||||
'''Create a k8s secret with Docker Hub credentials.
|
||||
|
||||
Check the file $HOME/.docker/config.json for Docker Hub
|
||||
credentials. If if found, create the secret and return
|
||||
its name. Otherwise, do nothing and return None.
|
||||
'''
|
||||
|
||||
cred_name = self.__get_docker_cred_secret_name()
|
||||
|
||||
# Create a temporary docker config file that contains only the
|
||||
# docker hub credentials, by extracting it from the calling user's
|
||||
# docker config
|
||||
|
||||
# Find docker config location
|
||||
docker_config = '%s/config.json' % \
|
||||
os.getenv('DOCKER_CONFIG',
|
||||
os.path.expanduser('~/.docker'))
|
||||
try:
|
||||
with open(docker_config) as f:
|
||||
docker_config_data = json.load(f)
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
|
||||
# Look for dockerhub credentials
|
||||
dockerhub_auth = docker_config_data.get('auths', {})\
|
||||
.get('https://index.docker.io/v1/', {})\
|
||||
.get('auth')
|
||||
if not dockerhub_auth:
|
||||
return None
|
||||
|
||||
# Create a temporary file that contains only docker hub credentials
|
||||
with tempfile.NamedTemporaryFile(mode='w+t',
|
||||
encoding='utf8',
|
||||
prefix='stx_docker_config_',
|
||||
suffix='.json') as f:
|
||||
new_docker_config_data = {
|
||||
'auths': {
|
||||
'https://index.docker.io/v1/': {
|
||||
'auth': dockerhub_auth
|
||||
}
|
||||
}
|
||||
}
|
||||
json.dump(new_docker_config_data, f)
|
||||
f.flush()
|
||||
|
||||
# (re-)create the secret
|
||||
self.__delete_docker_cred_secret(cred_name)
|
||||
create_cmd = self.config.kubectl() + f' create secret generic {cred_name}' + \
|
||||
f' --from-file=.dockerconfigjson="{f.name}"' + \
|
||||
' --type=kubernetes.io/dockerconfigjson'
|
||||
logger.info('Running: %s', create_cmd)
|
||||
subprocess.run(create_cmd, shell=True, check=True)
|
||||
|
||||
return cred_name
|
||||
|
||||
def delete_docker_cred_secret(self):
|
||||
'''Delete the docker secret from k8s
|
||||
|
||||
Do nothing if it doesn't exist.
|
||||
'''
|
||||
self.__delete_docker_cred_secret(self.__get_docker_cred_secret_name())
|
||||
|
||||
def __delete_docker_cred_secret(self, cred_name):
|
||||
delete_cmd = self.config.kubectl() + \
|
||||
f' delete secret {cred_name} --ignore-not-found'
|
||||
try:
|
||||
logger.info('Running: %s', delete_cmd)
|
||||
subprocess.run(delete_cmd, shell=True,
|
||||
stderr=subprocess.PIPE, check=True,
|
||||
encoding='utf8', errors='utf8')
|
||||
except subprocess.CalledProcessError as x:
|
||||
logger.error('Failed while attempting to delete k8s ' +
|
||||
'credentials "%s": %s', cred_name, x.stderr)
|
||||
raise x
|
||||
|
||||
def helm_release_exists(self, projectname):
|
||||
'''Check if the helm release exists'''
|
||||
|
||||
|
@ -251,7 +251,7 @@ stx-pkgbuilder/configmap/')
|
||||
|
||||
return repomgr_type
|
||||
|
||||
def handleStartTask(self, projectname, wait):
|
||||
def handleStartTask(self, projectname, wait, use_dockerhub_cred):
|
||||
if self.config.use_minikube:
|
||||
self.minikube_ctl.start()
|
||||
|
||||
@ -271,6 +271,11 @@ stx-pkgbuilder/configmap/')
|
||||
if self.config.container_mtu:
|
||||
cmd += f' --set stx-docker.mtu={self.config.container_mtu}'
|
||||
|
||||
if use_dockerhub_cred:
|
||||
image_pull_secret = self.k8s.try_create_docker_cred_secret()
|
||||
if image_pull_secret:
|
||||
cmd += f' --set global.imagePullSecrets[0].name={image_pull_secret}'
|
||||
|
||||
self.logger.debug('Execute the helm start command: %s', cmd)
|
||||
helm_status = self.k8s.helm_release_exists(self.projectname)
|
||||
if helm_status:
|
||||
@ -317,6 +322,8 @@ stx-pkgbuilder/configmap/')
|
||||
self.logger.info("waiting for %d pod(s) to exit", pod_count)
|
||||
time.sleep(2)
|
||||
|
||||
self.k8s.delete_docker_cred_secret()
|
||||
|
||||
def handleIsStartedTask(self, projectname):
|
||||
if self.k8s.helm_release_exists(projectname):
|
||||
self.logger.info('Helm release %s is installed' % projectname)
|
||||
@ -420,7 +427,8 @@ no lat container is available!')
|
||||
projectname = 'stx'
|
||||
|
||||
if args.ctl_task == 'start':
|
||||
self.handleStartTask(projectname, args.wait)
|
||||
self.handleStartTask(projectname, args.wait,
|
||||
args.use_dockerhub_cred)
|
||||
|
||||
elif args.ctl_task == 'stop':
|
||||
self.handleStopTask(projectname, args.wait)
|
||||
|
@ -84,6 +84,12 @@ task.\t\teg: [start|enter|stop|is-started|status|upgrade|keys-add]')
|
||||
help='wait for operation to finish, ' +
|
||||
'for start, stop\n\n',
|
||||
action='store_true')
|
||||
control_subparser.add_argument('--use-dockerhub-cred',
|
||||
help='Use dockerhub credentials from ' +
|
||||
'$HOME/.docker/config for pulling ' +
|
||||
'environment pods\' images within ' +
|
||||
'k8s (for "start" command only)\n\n',
|
||||
action='store_true')
|
||||
control_subparser.set_defaults(handle=self.handlecontrol.handleControl)
|
||||
|
||||
config_subparser = subparsers.add_parser('config',
|
||||
|
@ -21,7 +21,7 @@ spec:
|
||||
labels:
|
||||
{{- include "stx-repomgr.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
{{- with (.Values.imagePullSecrets | default .Values.global.imagePullSecrets) }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
|
@ -21,7 +21,7 @@ spec:
|
||||
labels:
|
||||
{{- include "stx-builder-files-http.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
{{- with (.Values.imagePullSecrets | default .Values.global.imagePullSecrets) }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
|
@ -21,7 +21,7 @@ spec:
|
||||
labels:
|
||||
{{- include "stx-docker.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
{{- with (.Values.imagePullSecrets | default .Values.global.imagePullSecrets) }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
|
@ -21,7 +21,7 @@ spec:
|
||||
labels:
|
||||
{{- include "stx-lat-tool.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
{{- with (.Values.imagePullSecrets | default .Values.global.imagePullSecrets) }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
|
@ -21,7 +21,7 @@ spec:
|
||||
labels:
|
||||
{{- include "stx-pkgbuilder.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
{{- with (.Values.imagePullSecrets | default .Values.global.imagePullSecrets) }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
|
@ -21,7 +21,7 @@ spec:
|
||||
labels:
|
||||
{{- include "stx-repomgr.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
{{- with (.Values.imagePullSecrets | default .Values.global.imagePullSecrets) }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
|
Loading…
x
Reference in New Issue
Block a user